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


以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android自定義View實現(xiàn)簡單炫酷的球體進度球實例代碼
這篇文章主要給大家介紹了關于Android自定義View實現(xiàn)簡單炫酷的球體進度球的相關資料,文中通過示例代碼介紹的非常詳細,對各位Android開發(fā)者們具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-01-01
Android?startActivityForResult的調用與封裝詳解
startActivityForResult?可以說是我們常用的一種操作了,目前有哪些方式實現(xiàn)?startActivityForResult?的功能呢?本文就來和大家詳細聊聊2023-03-03
Android實現(xiàn)App中導航Tab欄懸浮的功能
相信大家在玩手機的過程中應該會注意到很多的app都有這種功能,比如說外賣達人常用的“餓了么”。所以這篇文章給大家分享了Android如何實現(xiàn)app中的導航Tab欄懸浮的功能,有需要的朋友們可以參考借鑒。2016-10-10
21天學習android開發(fā)教程之SurfaceView
21天學習android開發(fā)教程之SurfaceView,SurfaceView由于可以直接從內存或者DMA等硬件接口取得圖像數(shù)據(jù),因此是個非常重要的繪圖容器,操作相對簡單,感興趣的小伙伴們可以參考一下2016-02-02
Android連接MySQL數(shù)據(jù)庫并進行增刪改查操作示例講解
這篇文章主要介紹了Android 連接MySQL數(shù)據(jù)庫并進行增刪改查操作示例講解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-08-08

