使用Flutter怎么實(shí)現(xiàn)一個(gè)底部導(dǎo)航?相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。
成都創(chuàng)新互聯(lián)公司是專業(yè)的陸良網(wǎng)站建設(shè)公司,陸良接單;提供網(wǎng)站制作、網(wǎng)站建設(shè),網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行陸良網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
創(chuàng)建navigation_icon_view.dart文件,定義一個(gè)NavigationIconView類,用于管理BottomNavigationBarItem(底部導(dǎo)航欄項(xiàng)目)控件的樣式、行為與動(dòng)畫。
import 'package:flutter/material.dart'; // 創(chuàng)建類,導(dǎo)航圖標(biāo)視圖 class NavigationIconView { // 導(dǎo)航圖標(biāo)視圖的構(gòu)造函數(shù) NavigationIconView({ // 控件參數(shù),傳遞圖標(biāo) Widget icon, // 控件參數(shù),傳遞標(biāo)題 Widget title, // 控件參數(shù),傳遞顏色 Color color, /* * Ticker提供者 * 由類實(shí)現(xiàn)的接口,可以提供Ticker對象 * Ticker對象:每個(gè)動(dòng)畫幀調(diào)用它的回調(diào)一次 */ TickerProvider vsync, }):_icon = icon, //接收傳遞的圖標(biāo) // 接收傳遞的顏色 _color = color, // 創(chuàng)建底部導(dǎo)航欄項(xiàng)目 item = new BottomNavigationBarItem( // 項(xiàng)目的圖標(biāo) icon: icon, // 項(xiàng)目的標(biāo)題 title: title ), // 創(chuàng)建動(dòng)畫控制器 controller = new AnimationController( // 動(dòng)畫持續(xù)的時(shí)間長度:默認(rèn)情況下主題更改動(dòng)畫的持續(xù)時(shí)間 duration: kThemeAnimationDuration, // 垂直同步 vsync: vsync, ) { // 創(chuàng)建曲線動(dòng)畫 _animation = new CurvedAnimation( // 應(yīng)用曲線動(dòng)畫的動(dòng)畫 parent: controller, /* * 正向使用的曲線: * 從0.5 * 到1.0結(jié)束 * 應(yīng)用的曲線:快速啟動(dòng)并緩和到最終位置的曲線 */ curve: new Interval(0.5, 1.0, curve: Curves.fastOutSlowIn), ); } // 類成員,存儲(chǔ)圖標(biāo) final Widget _icon; // 類成員,存儲(chǔ)顏色 final Color _color; // 類成員,底部導(dǎo)航欄項(xiàng)目 final BottomNavigationBarItem item; // 類成員,動(dòng)畫控制器 final AnimationController controller; // 類成員,曲線動(dòng)畫 CurvedAnimation _animation; /* * 類函數(shù),過渡轉(zhuǎn)換 * BottomNavigationBarType:定義底部導(dǎo)航欄的布局和行為 * BuildContext:處理控件樹中的控件 */ FadeTransition transition(BottomNavigationBarType type, BuildContext context) { // 局部變量,存儲(chǔ)圖標(biāo)顏色 Color iconColor; // 如果底部導(dǎo)航欄的位置和大小在點(diǎn)擊時(shí)會(huì)變大 if (type == BottomNavigationBarType.shifting) { // 存儲(chǔ)顏色作為圖標(biāo)顏色 iconColor = _color; } else { /* * 保存質(zhì)感設(shè)計(jì)主題的顏色和排版值: * 使用ThemeData來配置主題控件 * 使用Theme.of獲取當(dāng)前主題 */ final ThemeData themeData = Theme.of(context); /* * 如果程序整體主題的亮度很高(需要深色文本顏色才能實(shí)現(xiàn)可讀的對比度) * 就返回程序主要部分的背景顏色作為圖標(biāo)顏色 * 否則返回控件的前景顏色作為圖標(biāo)顏色 */ iconColor = themeData.brightness == Brightness.light ? themeData.primaryColor : themeData.accentColor; } // 返回值,創(chuàng)建不透明度轉(zhuǎn)換 return new FadeTransition( // 控制子控件不透明度的動(dòng)畫 opacity: _animation, // 子控件:創(chuàng)建滑動(dòng)轉(zhuǎn)換過渡 child: new SlideTransition( /* * 控制子控件位置的動(dòng)畫 * 開始值和結(jié)束值之間的線性插值<以尺寸的分?jǐn)?shù)表示的偏移量> * (1.0,0.0)表示Size的右上角 * (0.0,1.0)表示Size的左下角 */ position: new Tween( // 此變量在動(dòng)畫開頭的值 begin: const FractionalOffset(0.0, 0.02), // 此變量在動(dòng)畫結(jié)尾處的值:左上角 end: FractionalOffset.topLeft, ).animate(_animation), // 返回給定動(dòng)畫,該動(dòng)畫接受由此對象確定的值 // 子控件:創(chuàng)建控制子控件的顏色,不透明度和大小的圖標(biāo)主題 child: new IconTheme( // 用于子控件中圖標(biāo)的顏色,不透明度和大小 data: new IconThemeData( // 圖標(biāo)的默認(rèn)顏色 color: iconColor, // 圖標(biāo)的默認(rèn)大小 size: 120.0, ), // 子控件 child: _icon, ) ) ); } }
再創(chuàng)建main.dart文件。類CustomIcon創(chuàng)建一個(gè)容器控件,作為一個(gè)自定義的圖標(biāo)使用。同時(shí)使用質(zhì)感設(shè)計(jì)的彈出菜單控件切換底部導(dǎo)航欄的行為和樣式。
import 'package:flutter/material.dart'; import 'navigation_icon_view.dart'; // 創(chuàng)建類,自定義圖標(biāo),繼承StatelessWidget(無狀態(tài)的控件) class CustomIcon extends StatelessWidget { // 覆蓋此函數(shù)以構(gòu)建依賴于動(dòng)畫的當(dāng)前狀態(tài)的控件 @override Widget build(BuildContext context) { // 獲取當(dāng)前圖標(biāo)主題,創(chuàng)建與此圖標(biāo)主題相同的圖標(biāo)主題 final IconThemeData iconTheme = IconTheme.of(context).fallback(); // 返回值,創(chuàng)建一個(gè)容器控件 return new Container( // 圍繞子控件的填充:每個(gè)邊都偏移4.0 margin: const EdgeInsets.all(4.0), // 容器寬度:圖標(biāo)主題的寬度減8.0 width: iconTheme.size - 8.0, // 容器高度:圖標(biāo)主題的高度減8.0 height: iconTheme.size - 8.0, // 子控件的裝飾:創(chuàng)建一個(gè)裝飾 decoration: new BoxDecoration( // 背景顏色:圖標(biāo)主題的顏色 backgroundColor: iconTheme.color ) ); } } // 創(chuàng)建類,菜單演示,繼承StatefulWidget(有狀態(tài)的控件) class MenusDemo extends StatefulWidget { /* * 覆蓋具有相同名稱的超類成員 * createState方法在樹中的給定位置為此控件創(chuàng)建可變狀態(tài) * 子類應(yīng)重寫此方法以返回其關(guān)聯(lián)的State子類新創(chuàng)建的實(shí)例 */ @override _MenusDemoState createState() => new _MenusDemoState(); } /* * 關(guān)聯(lián)State子類的實(shí)例 * 繼承State:StatefulWidget(有狀態(tài)的控件)邏輯和內(nèi)部狀態(tài) * 繼承TickerProviderStateMixin,提供Ticker對象 */ class _MenusDemoState extends Statewith TickerProviderStateMixin { // 類成員,存儲(chǔ)底部導(dǎo)航欄的當(dāng)前選擇 int _currentIndex = 2; // 類成員,存儲(chǔ)底部導(dǎo)航欄的布局和行為:在點(diǎn)擊時(shí)會(huì)變大 BottomNavigationBarType _type = BottomNavigationBarType.shifting; // 類成員,存儲(chǔ)NavigationIconView類的列表 List _navigationViews; /* * 在對象插入到樹中時(shí)調(diào)用 * 框架將為它創(chuàng)建的每個(gè)State(狀態(tài))對象調(diào)用此方法一次 * 覆蓋此方法可以實(shí)現(xiàn)此對象被插入到樹中的位置的初始化 * 或用于配置此對象上的控件的位置的初始化 */ @override void initState() { // 調(diào)用父類的內(nèi)容 super.initState(); // 在存儲(chǔ)NavigationIconView類的列表里添加內(nèi)容 _navigationViews = [ /* * 創(chuàng)建NavigationIconView類的實(shí)例 * 傳遞圖標(biāo)參數(shù) * 傳遞標(biāo)題參數(shù) * 傳遞顏色參數(shù) * 傳遞Ticker對象 */ new NavigationIconView( icon: new Icon(Icons.access_alarm), title: new Text('成就'), color: Colors.deepPurple[500], vsync: this, ), new NavigationIconView( icon: new CustomIcon(), title: new Text('行動(dòng)'), color: Colors.deepOrange[500], vsync: this, ), new NavigationIconView( icon: new Icon(Icons.cloud), title: new Text('人物'), color: Colors.teal[500], vsync: this, ), new NavigationIconView( icon: new Icon(Icons.favorite), title: new Text('財(cái)產(chǎn)'), color: Colors.indigo[500], vsync: this, ), new NavigationIconView( icon: new Icon(Icons.event_available), title: new Text('設(shè)置'), color: Colors.pink[500], vsync: this, ), ]; // 循環(huán)調(diào)用存儲(chǔ)NavigationIconView類的列表的值 for (NavigationIconView view in _navigationViews) // 每次動(dòng)畫控制器的值更改時(shí)調(diào)用偵聽器 view.controller.addListener(_rebuild); // 底部導(dǎo)航欄當(dāng)前選擇的動(dòng)畫控制器的值為1.0 _navigationViews[_currentIndex].controller.value = 1.0; } // 釋放此對象使用的資源 @override void dispose() { // 調(diào)用父類的內(nèi)容 super.dispose(); // 循環(huán)調(diào)用存儲(chǔ)NavigationIconView類的列表中的項(xiàng) for (NavigationIconView view in _navigationViews) // 調(diào)用此方法后,對象不再可用 view.controller.dispose(); } // 動(dòng)畫控制器的值更改時(shí)的操作 void _rebuild() { // 通知框架此對象的內(nèi)部狀態(tài)已更改 setState((){ // 重建,以便為視圖創(chuàng)建動(dòng)畫 }); } // 建立過渡堆棧 Widget _buildTransitionsStack() { // 局部變量,存儲(chǔ)不透明度轉(zhuǎn)換的列表 final List transitions = []; // 循環(huán)調(diào)用存儲(chǔ)NavigationIconView類的列表的值 for (NavigationIconView view in _navigationViews) // 在存儲(chǔ)不透明度轉(zhuǎn)換的列表中添加transition函數(shù)的返回值 transitions.add(view.transition(_type, context)); // 對存儲(chǔ)不透明度轉(zhuǎn)換的列表進(jìn)行排序 transitions.sort((FadeTransition a, FadeTransition b) { final Animation aAnimation = a.listenable; final Animation bAnimation = b.listenable; // aValue:a的動(dòng)畫值 double aValue = aAnimation.value; // bValue:b的動(dòng)畫值 double bValue = bAnimation.value; /* * 將aValue與bValue進(jìn)行比較 * 返回一個(gè)負(fù)整數(shù),aValue排序在bValue之前 * 返回一個(gè)正整數(shù),aValue排序在bValue之后 */ return aValue.compareTo(bValue); }); // 返回值,創(chuàng)建層疊布局控件 return new Stack(children: transitions); } // 覆蓋此函數(shù)以構(gòu)建依賴于動(dòng)畫的當(dāng)前狀態(tài)的控件 @override Widget build(BuildContext context) { // 局部變量,創(chuàng)建底部導(dǎo)航欄 final BottomNavigationBar botNavBar = new BottomNavigationBar( /* * 在底部導(dǎo)航欄中布置的交互項(xiàng):迭代存儲(chǔ)NavigationIconView類的列表 * 返回此迭代的每個(gè)元素的底部導(dǎo)航欄項(xiàng)目 * 創(chuàng)建包含此迭代的元素的列表 */ items: _navigationViews .map((NavigationIconView navigationView) => navigationView.item) .toList(), // 當(dāng)前活動(dòng)項(xiàng)的索引:存儲(chǔ)底部導(dǎo)航欄的當(dāng)前選擇 currentIndex: _currentIndex, // 底部導(dǎo)航欄的布局和行為:存儲(chǔ)底部導(dǎo)航欄的布局和行為 type: _type, // 當(dāng)點(diǎn)擊項(xiàng)目時(shí)調(diào)用的回調(diào) onTap: (int index) { // 通知框架此對象的內(nèi)部狀態(tài)已更改 setState((){ // 當(dāng)前選擇的底部導(dǎo)航欄項(xiàng)目,開始反向運(yùn)行此動(dòng)畫 _navigationViews[_currentIndex].controller.reverse(); // 更新存儲(chǔ)底部導(dǎo)航欄的當(dāng)前選擇 _currentIndex = index; // 當(dāng)前選擇的底部導(dǎo)航欄項(xiàng)目,開始向前運(yùn)行此動(dòng)畫 _navigationViews[_currentIndex].controller.forward(); }); } ); // 實(shí)現(xiàn)基本的質(zhì)感設(shè)計(jì)視覺布局結(jié)構(gòu) return new Scaffold( // 質(zhì)感設(shè)計(jì)應(yīng)用欄 appBar: new AppBar( // 應(yīng)用欄中顯示的主要控件,包含程序當(dāng)前內(nèi)容描述的文本 title: new Text('底部導(dǎo)航演示'), // 在標(biāo)題控件后顯示的控件 actions: [ // 創(chuàng)建一個(gè)顯示彈出式菜單的按鈕 new PopupMenuButton ( // 當(dāng)用戶從此按鈕創(chuàng)建的彈出菜單中選擇一個(gè)值時(shí)調(diào)用 onSelected: (BottomNavigationBarType value) { // 通知框架此對象的內(nèi)部狀態(tài)已更改 setState((){ // 存儲(chǔ)底部導(dǎo)航欄的布局和行為:選擇值 _type = value; }); }, // 點(diǎn)擊彈出菜單中顯示的項(xiàng)目時(shí)調(diào)用 itemBuilder: (BuildContext context) => > [ /* * 彈出菜單中的顯示項(xiàng)目 * 返回值:底部導(dǎo)航欄的布局和行為 * 子控件:文本控件 */ new PopupMenuItem ( value: BottomNavigationBarType.fixed, child: new Text('Fixed') ), new PopupMenuItem ( value: BottomNavigationBarType.shifting, child: new Text('Shifting') ) ] ) ] ), // 主要內(nèi)容 body: new Center( // 主要內(nèi)容:_buildTransitionsStack函數(shù)的返回值 child: _buildTransitionsStack() ), // 水平的按鈕數(shù)組,沿著程序的底部顯示 bottomNavigationBar: botNavBar, ); } } // 程序入口 void main() { // 創(chuàng)建質(zhì)感設(shè)計(jì)程序,并放置到主屏幕 runApp(new MaterialApp( // 在窗口管理器中使用此應(yīng)用程序的單行描述 title: 'Flutter教程', // 程序的默認(rèn)路由的控件 home: new MenusDemo(), )); }
看完上述內(nèi)容,你們掌握使用Flutter怎么實(shí)現(xiàn)一個(gè)底部導(dǎo)航的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!