Flutter實(shí)現(xiàn)底部菜單導(dǎo)航
簡(jiǎn)介
現(xiàn)在我們的 APP 上面都會(huì)在屏幕下方有一排的按鈕,點(diǎn)擊不同的按鈕可以進(jìn)入不同的界面。就是說(shuō)在界面的底部會(huì)有一排的按鈕導(dǎo)航。可看下面的圖示。
完成圖示

程序工程目錄

梳理下實(shí)現(xiàn)步驟
我們需要實(shí)現(xiàn)這個(gè)底部菜單導(dǎo)航,就需要有底部菜單的那一排圖標(biāo)按鈕。圖標(biāo)按鈕是固定在一個(gè)工具欄 “bar” 上面。然后呢,需要分別需要有按鈕對(duì)應(yīng)的界面,就是說(shuō)按鈕有多少個(gè),那么界面需要對(duì)應(yīng)的有多少個(gè)。我們來(lái)一個(gè)清單列表:
- 按鈕圖標(biāo)區(qū)域。由于展示的方式都是一樣的,我們需要有一個(gè)單獨(dú)的控件,循環(huán)出來(lái)就好。
- 工具欄區(qū)域。用于展示按鈕圖標(biāo),并且能固定在底部。
- 首頁(yè)。用于將工具欄放入界面中,并且將按鈕對(duì)應(yīng)的界面作為它的子元素存放于其中。
- 不同的按鈕對(duì)應(yīng)的界面。在我們點(diǎn)擊的圖標(biāo)按鈕的時(shí)候,展示不同的界面。
我們底部的按鈕是不會(huì)刷新的,界面會(huì)刷新,如何實(shí)現(xiàn)?
我們界面展示區(qū)域分為兩塊,一塊展示底部的工具欄,一塊展示頁(yè)面。下面代碼實(shí)現(xiàn):
return new MaterialApp(
home: new Scaffold(
body: new Center(
child: _currentPage // 動(dòng)態(tài)的展示我們當(dāng)前的頁(yè)面
),
bottomNavigationBar: bottomNavigationBar, // 底部工具欄
),
theme: new ThemeData(
primarySwatch: Colors.blue, // 設(shè)置主題顏色
),
);
具體實(shí)現(xiàn)
第一步:創(chuàng)建一個(gè) flutter 工程
可以按照工程目錄圖中的結(jié)構(gòu),將對(duì)應(yīng)的文件建好。
第二步:修改 main.dart。
main.dart 是我們程序的入口。就類似于 Java、C 中的 main() ,作為一個(gè)程序的入口。我們將 main.dart 作為程序的啟動(dòng)入口,就不做過(guò)多的操作,只是指定去加載我們的首頁(yè)(index.dart)。
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_demo/index/index.dart'; // 導(dǎo)入index.dart
// 這里為入口函數(shù)
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new Index(), // 指定去加載 Index頁(yè)面。
);
}
}第三步:創(chuàng)建 NavigationIconView。
正如前面說(shuō)的,我們底部的按鈕區(qū)域展示的圖標(biāo)加上文字是固定格式,所以將這一部分抽取出來(lái),作為一個(gè)公共的 class,方便界面程序維護(hù)。
navigation_icon_view.dart
import 'package:flutter/material.dart';
// 創(chuàng)建一個(gè) Icon 展示控件
class NavigationIconView {
// 創(chuàng)建兩個(gè)屬性,一個(gè)是 用來(lái)展示 icon, 一個(gè)是動(dòng)畫處理
final BottomNavigationBarItem item;
final AnimationController controller;
// 類似于 java 中的構(gòu)造方法
// 創(chuàng)建 NavigationIconView 需要傳入三個(gè)參數(shù), icon 圖標(biāo),title 標(biāo)題, TickerProvider
NavigationIconView({Widget icon, Widget title, TickerProvider vsync}):
item = new BottomNavigationBarItem(
icon: icon,
title: title,
),
controller = new AnimationController(
duration: kThemeAnimationDuration, // 設(shè)置動(dòng)畫持續(xù)的時(shí)間
vsync: vsync // 默認(rèn)屬性和參數(shù)
);
}第四步:創(chuàng)建 Index
這一步就比較重要了,因?yàn)槲覀冃枰谶@個(gè)界面上面去布局,以及實(shí)現(xiàn)點(diǎn)擊按鈕圖標(biāo)之后,有事件觸發(fā)。正因?yàn)槲覀冃枰惺录|發(fā),所以創(chuàng)建一個(gè)帶有狀態(tài)的 Widget(StatefulWidget)。下面的代碼注釋給的很詳細(xì)了,可以仔細(xì)看。
index.dart
import 'package:flutter/material.dart';
import 'package:flutter_demo/NoticePage/notice_page.dart';
import 'package:flutter_demo/home/home_page.dart';
import 'package:flutter_demo/idea/idea_page.dart';
import 'package:flutter_demo/market/market_page.dart';
import 'package:flutter_demo/my/my_page.dart';
import 'navigation_icon_view.dart'; // 如果是在同一個(gè)包的路徑下,可以直接使用對(duì)應(yīng)的文件名
// 創(chuàng)建一個(gè) 帶有狀態(tài)的 Widget Index
class Index extends StatefulWidget {
// 固定的寫法
@override
State<StatefulWidget> createState() => new _IndexState();
}
// 要讓主頁(yè)面 Index 支持動(dòng)效,要在它的定義中附加mixin類型的對(duì)象TickerProviderStateMixin
class _IndexState extends State<Index> with TickerProviderStateMixin{
int _currentIndex = 0; // 當(dāng)前界面的索引值
List<NavigationIconView> _navigationViews; // 底部圖標(biāo)按鈕區(qū)域
List<StatefulWidget> _pageList; // 用來(lái)存放我們的圖標(biāo)對(duì)應(yīng)的頁(yè)面
StatefulWidget _currentPage; // 當(dāng)前的顯示頁(yè)面
// 定義一個(gè)空的設(shè)置狀態(tài)值的方法
void _rebuild() {
setState((){});
}
@override
void initState() {
super.initState();
// 初始化導(dǎo)航圖標(biāo)
_navigationViews = <NavigationIconView>[
new NavigationIconView(icon: new Icon(Icons.assessment), title: new Text("首頁(yè)"), vsync: this), // vsync 默認(rèn)屬性和參數(shù)
new NavigationIconView(icon: new Icon(Icons.all_inclusive), title: new Text("想法"), vsync: this),
new NavigationIconView(icon: new Icon(Icons.add_shopping_cart), title: new Text("市場(chǎng)"), vsync: this),
new NavigationIconView(icon: new Icon(Icons.add_alert), title: new Text("通知"), vsync: this),
new NavigationIconView(icon: new Icon(Icons.perm_identity), title: new Text("我的"), vsync: this),
];
// 給每一個(gè)按鈕區(qū)域加上監(jiān)聽
for (NavigationIconView view in _navigationViews) {
view.controller.addListener(_rebuild);
}
// 將我們 bottomBar 上面的按鈕圖標(biāo)對(duì)應(yīng)的頁(yè)面存放起來(lái),方便我們?cè)邳c(diǎn)擊的時(shí)候
_pageList = <StatefulWidget>[
new HomePage(),
new IdeaPage(),
new MarketPage(),
new NoticePage(),
new MyPage()
];
_currentPage = _pageList[_currentIndex];
}
@override
Widget build(BuildContext context) {
// 聲明定義一個(gè) 底部導(dǎo)航的工具欄
final BottomNavigationBar bottomNavigationBar = new BottomNavigationBar(
items: _navigationViews
.map((NavigationIconView navigationIconView) => navigationIconView.item)
.toList(), // 添加 icon 按鈕
currentIndex: _currentIndex, // 當(dāng)前點(diǎn)擊的索引值
type: BottomNavigationBarType.fixed, // 設(shè)置底部導(dǎo)航工具欄的類型:fixed 固定
onTap: (int index){ // 添加點(diǎn)擊事件
setState((){ // 點(diǎn)擊之后,需要觸發(fā)的邏輯事件
_navigationViews[_currentIndex].controller.reverse();
_currentIndex = index;
_navigationViews[_currentIndex].controller.forward();
_currentPage = _pageList[_currentIndex];
});
},
);
return new MaterialApp(
home: new Scaffold(
body: new Center(
child: _currentPage // 動(dòng)態(tài)的展示我們當(dāng)前的頁(yè)面
),
bottomNavigationBar: bottomNavigationBar, // 底部工具欄
),
theme: new ThemeData(
primarySwatch: Colors.blue, // 設(shè)置主題顏色
),
);
}
}第四步:創(chuàng)建頁(yè)面
前面的步驟都是在搭建我們的基礎(chǔ),現(xiàn)在是做展示界面。由于不同的界面,對(duì)應(yīng)的源碼都是和下面的是一樣的,只是 class 的名字不一樣,就都可以使用同樣的模版復(fù)制過(guò)去就有可以了。
home_page.dart
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget{
@override
State<StatefulWidget> createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('首頁(yè)'),
actions: <Widget>[
new Container()
],
),
body: new Center(
child: null,
),
),
);
}
}idea_page.dart
import 'package:flutter/material.dart';
class IdeaPage extends StatefulWidget{
@override
State<StatefulWidget> createState() => new _IdeaPageState();
}
class _IdeaPageState extends State<IdeaPage> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('想法'),
actions: <Widget>[
new Container()
],
),
body: new Center(
child: null,
),
),
);
}
}market_page.dart
import 'package:flutter/material.dart';
class MarketPage extends StatefulWidget{
@override
State<StatefulWidget> createState() => new _MarketPageState();
}
class _MarketPageState extends State<MarketPage> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('市場(chǎng)'),
// 后面的省略
// ......
)
),
);
}
}剩下的界面都是一樣子的了,就不貼出來(lái)了,都是復(fù)制一下,改了一個(gè)類名,和顯示的文字而已。
第五步:啟動(dòng)測(cè)試
到此我們就完成了,可以啟動(dòng)程序,看下效果。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
android 手機(jī)SD卡讀寫操作(以txt文本為例)實(shí)現(xiàn)步驟
要完成SD卡讀寫操作首先對(duì)manifest注冊(cè)SD卡讀寫權(quán)限其次是創(chuàng)建一個(gè)對(duì)SD卡中文件讀寫的類寫一個(gè)用于檢測(cè)讀寫功能的的布局然后就是UI的類了,感興趣的朋友可以參考下,希望可以幫助到你2013-02-02
Android編程實(shí)現(xiàn)給Button添加圖片和文字的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)給Button添加圖片和文字的方法,涉及Android針對(duì)按鈕元素屬性的相關(guān)操作技巧,需要的朋友可以參考下2015-11-11
ActivityLifecycleCallbacks如何判斷APP是否在前臺(tái)
這篇文章主要為大家詳細(xì)介紹了ActivityLifecycleCallbacks判斷APP是否在前臺(tái)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
通過(guò)FancyView提供 Android 酷炫的開屏動(dòng)畫實(shí)例代碼
這篇文章主要介紹了通過(guò)FancyView提供 Android 酷炫的開屏動(dòng)畫的實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-12-12
Android 自定義組件衛(wèi)星菜單的實(shí)現(xiàn)
這篇文章主要介紹了Android 自定義組件衛(wèi)星菜單的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-07-07
Android Kotlin開發(fā)實(shí)例(Hello World!)及語(yǔ)法詳解
這篇文章主要介紹了Android Kotlin開發(fā)實(shí)例及語(yǔ)法詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05
Android 連接藍(lán)牙掃碼器無(wú)輸入框的實(shí)現(xiàn)
這篇文章主要介紹了Android 連接藍(lán)牙掃碼器無(wú)輸入框的實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02
Android原生ViewPager控件實(shí)現(xiàn)卡片翻動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了Android原生ViewPager控件實(shí)現(xiàn)卡片翻動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07

