Flutter常用元件總結-底部導航欄BottomNavigationBar元件
技術標籤:Flutter
示例頁面目錄如下:
在入口檔案main.dart中使用我們定義的widget元件類BottomNavigationWidget():
import 'package:flutter/material.dart'; import './mywidget/bottom_navigation_widget.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Container( child: MaterialApp( title: '優品酒家', debugShowCheckedModeBanner: false, theme: ThemeData( primaryColor: Colors.pink ), home: BottomNavigationWidget(), ), ); } }
下面是與底部導航欄4個導航按鈕一一對應的頁面的home_page.dart、picture_page.dart、friend_page.dart、share_page.dart,這裡只給出前兩個頁面,後兩個頁面的內容與第二個頁面的內容一樣,只是文字顯示改了一下,不再給出:
home_page.dart:
import 'package:flutter/material.dart'; import '../pages/goods_detail.dart'; class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title:Text('優品酒家')), body: new Center( child: RaisedButton( child: new Text("檢視商品詳情"), onPressed: (){ Navigator.push(context, new MaterialPageRoute(builder: (context)=>new GoodsDetail())); }, ), ) ); } }
picture_page.dart:
import 'package:flutter/material.dart'; class PicturePage extends StatefulWidget { @override _PicturePageState createState() => _PicturePageState(); } class _PicturePageState extends State<PicturePage> { @override Widget build(BuildContext context) { return Container( child: Center( child: Text("圖片頁"), ), ); } }
下面就是我們重點的內容BottomNavigationBar元件,同樣先通過原始碼定義類來認識:
class BottomNavigationBar extends StatefulWidget {
/// Creates a bottom navigation bar which is typically used as a
/// [Scaffold]'s [Scaffold.bottomNavigationBar] argument.
///
/// The length of [items] must be at least two and each item's icon and title
/// must not be null.
///
/// If [type] is null then [BottomNavigationBarType.fixed] is used when there
/// are two or three [items], [BottomNavigationBarType.shifting] otherwise.
///
/// The [iconSize], [selectedFontSize], [unselectedFontSize], and [elevation]
/// arguments must be non-null and non-negative.
///
/// If [selectedLabelStyle.color] and [unselectedLabelStyle.color] values
/// are non-null, they will be used instead of [selectedItemColor] and
/// [unselectedItemColor].
///
/// If custom [IconThemData]s are used, you must provide both
/// [selectedIconTheme] and [unselectedIconTheme], and both
/// [IconThemeData.color] and [IconThemeData.size] must be set.
///
/// If both [selectedLabelStyle.fontSize] and [selectedFontSize] are set,
/// [selectedLabelStyle.fontSize] will be used.
///
/// Only one of [selectedItemColor] and [fixedColor] can be specified. The
/// former is preferred, [fixedColor] only exists for the sake of
/// backwards compatibility.
///
/// The [showSelectedLabels] argument must be non-null.
///
/// The [showUnselectedLabels] argument defaults to `true` if [type] is
/// [BottomNavigationBarType.fixed] and `false` if [type] is
/// [BottomNavigationBarType.shifting].
BottomNavigationBar({
Key key,
@required this.items,
this.onTap,
this.currentIndex = 0,
this.elevation,
this.type,
Color fixedColor,
this.backgroundColor,
this.iconSize = 24.0,
Color selectedItemColor,
this.unselectedItemColor,
this.selectedIconTheme,
this.unselectedIconTheme,
this.selectedFontSize = 14.0,
this.unselectedFontSize = 12.0,
this.selectedLabelStyle,
this.unselectedLabelStyle,
this.showSelectedLabels = true,
this.showUnselectedLabels,
this.mouseCursor,
}) : assert(items != null),
assert(items.length >= 2),
assert(
items.every((BottomNavigationBarItem item) => item.title != null) == true,
'Every item must have a non-null title',
),
assert(0 <= currentIndex && currentIndex < items.length),
assert(elevation == null || elevation >= 0.0),
assert(iconSize != null && iconSize >= 0.0),
assert(
selectedItemColor == null || fixedColor == null,
'Either selectedItemColor or fixedColor can be specified, but not both'
),
assert(selectedFontSize != null && selectedFontSize >= 0.0),
assert(unselectedFontSize != null && unselectedFontSize >= 0.0),
assert(showSelectedLabels != null),
selectedItemColor = selectedItemColor ?? fixedColor,
super(key: key);
/// Defines the appearance of the button items that are arrayed within the
/// bottom navigation bar.
final List<BottomNavigationBarItem> items;
/// Called when one of the [items] is tapped.
///
/// The stateful widget that creates the bottom navigation bar needs to keep
/// track of the index of the selected [BottomNavigationBarItem] and call
/// `setState` to rebuild the bottom navigation bar with the new [currentIndex].
final ValueChanged<int> onTap;
/// The index into [items] for the current active [BottomNavigationBarItem].
final int currentIndex;
/// The z-coordinate of this [BottomNavigationBar].
///
/// If null, defaults to `8.0`.
///
/// {@macro flutter.material.material.elevation}
final double elevation;
/// Defines the layout and behavior of a [BottomNavigationBar].
///
/// See documentation for [BottomNavigationBarType] for information on the
/// meaning of different types.
final BottomNavigationBarType type;
/// The value of [selectedItemColor].
///
/// This getter only exists for backwards compatibility, the
/// [selectedItemColor] property is preferred.
Color get fixedColor => selectedItemColor;
/// The color of the [BottomNavigationBar] itself.
///
/// If [type] is [BottomNavigationBarType.shifting] and the
/// [items]s, have [BottomNavigationBarItem.backgroundColor] set, the [item]'s
/// backgroundColor will splash and overwrite this color.
final Color backgroundColor;
/// The size of all of the [BottomNavigationBarItem] icons.
///
/// See [BottomNavigationBarItem.icon] for more information.
final double iconSize;
/// The color of the selected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.label].
///
/// If null then the [ThemeData.primaryColor] is used.
final Color selectedItemColor;
/// The color of the unselected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.label]s.
///
/// If null then the [TextTheme.caption]'s color is used.
final Color unselectedItemColor;
/// The size, opacity, and color of the icon in the currently selected
/// [BottomNavigationBarItem.icon].
///
/// If this is not provided, the size will default to [iconSize], the color
/// will default to [selectedItemColor].
///
/// It this field is provided, it must contain non-null [IconThemeData.size]
/// and [IconThemeData.color] properties. Also, if this field is supplied,
/// [unselectedIconTheme] must be provided.
final IconThemeData selectedIconTheme;
/// The size, opacity, and color of the icon in the currently unselected
/// [BottomNavigationBarItem.icon]s
///
/// If this is not provided, the size will default to [iconSize], the color
/// will default to [unselectedItemColor].
///
/// It this field is provided, it must contain non-null [IconThemeData.size]
/// and [IconThemeData.color] properties. Also, if this field is supplied,
/// [unselectedIconTheme] must be provided.
final IconThemeData unselectedIconTheme;
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are
/// selected.
final TextStyle selectedLabelStyle;
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are not
/// selected.
final TextStyle unselectedLabelStyle;
/// The font size of the [BottomNavigationBarItem] labels when they are selected.
///
/// If [selectedLabelStyle.fontSize] is non-null, it will be used instead of this.
///
/// Defaults to `14.0`.
final double selectedFontSize;
/// The font size of the [BottomNavigationBarItem] labels when they are not
/// selected.
///
/// If [unselectedLabelStyle.fontSize] is non-null, it will be used instead of this.
///
/// Defaults to `12.0`.
final double unselectedFontSize;
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
final bool showUnselectedLabels;
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
final bool showSelectedLabels;
/// The cursor for a mouse pointer when it enters or is hovering over the
/// tiles.
///
/// If this property is null, [SystemMouseCursors.click] will be used.
final MouseCursor mouseCursor;
@override
_BottomNavigationBarState createState() => _BottomNavigationBarState();
}
可以看出它定義了一些選中和未選中時的顏色、大小、樣式、主題,以及底部導航欄的背景顏色、點選事件,最重要的就是一個必須的導航item陣列,這個陣列的大小必須大於2,底部導航欄的顯示才可以顯示生效。
BottomNavigationBar
元件裡提供了一個相應事件onTap
,這個事件自帶一個索引值index
,通過索引值就可以和相應的頁面實現聯動切換。
下面會給出一個示例,在給出示例時,這裡需要明確一下有狀態元件StatefulWidget的個幾個概念:
(一)、Flutter元件分為有狀態和無狀態元件,專案開發常用的是有狀態元件。自定義的有狀態元件需要實現狀態控制器類後,再重寫 createState()方法。
(二)、Flutter開發的主要邏輯程式碼都會寫在狀態控制器類中,宣告變數、重寫方法、業務邏輯等。狀態控制器類的命名規則:
①類名前加字首"_" ②類名後加字尾State ③繼承State類,泛型引數中傳入類名。
下面給出在入口檔案中呼叫的BottomNavigationWidget(),底部導航欄示例:
import 'package:flutter/material.dart';
import 'package:flutter_app/pages/home_page.dart';
import 'package:flutter_app/pages/friend_page.dart';
import 'package:flutter_app/pages/share_page.dart';
import 'package:flutter_app/pages/picture_page.dart';
/// Flutter元件分為有狀態和無狀態元件,專案開發常用的是有狀態元件
/// 自定義的有狀態元件需要實現狀態控制器類後,重寫 createState()方法
class BottomNavigationWidget extends StatefulWidget {
@override
_BottomNavigationWidgetState createState() => _BottomNavigationWidgetState();
}
/// 主要的邏輯程式碼會寫在下面的狀態控制器類中
/// 狀態控制器類的命名規則:①類名前加字首"_" ②類名後加字尾State ③繼承State類,泛型引數中傳入類名
class _BottomNavigationWidgetState extends State<BottomNavigationWidget> {
final _bottomNavigationColor = Colors.pink;
int _currentIndex=0;
List<Widget> list=List();
@override
void initState() {
//使用構建者模式的鏈式呼叫,".."是Dart的語法,返回還是list物件
list..add(HomePage())..add(PicturePage())..add(FriendPage())..add(SharePage());
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: list[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home,color: _bottomNavigationColor,),
title:Text('首頁',style: TextStyle(color: _bottomNavigationColor)),),
BottomNavigationBarItem(
icon: Icon(Icons.email,color: _bottomNavigationColor,),
title:Text('頻道',style: TextStyle(color: _bottomNavigationColor),)),
BottomNavigationBarItem(icon: Icon(Icons.child_friendly,color: _bottomNavigationColor,),
title:Text('朋友圈',style: TextStyle(color: _bottomNavigationColor),)),
BottomNavigationBarItem(icon: Icon(Icons.share,color: _bottomNavigationColor,),
title:Text('分享',style: TextStyle(color: _bottomNavigationColor),))
],
/// BottomNavigationBar元件的點選事件onTap,事件自帶索引值index
/// 通過索引值index實現和list數組裡面的頁面例項的索引值一一對應,實現切換聯動
onTap:(int index){
setState(() {
_currentIndex=index;
});
},
///讓底部導航欄根據底部導航欄的item項的寬度設定固定寬度值,設定後底部的導航文字才能全部顯示
type:BottomNavigationBarType.fixed
),
);
}
}
注意:這裡重寫initState()
方法,把剛才做好的頁面進行初始化到一個Widget陣列中。有了陣列就可以根據陣列的索引來切換不同的頁面了。這是現在幾乎所有的APP採用的方式。
程式碼如下:
List<Widget> list = List();
@override
void initState(){
list..add(HomeScreen())..add(EmailScreen())..add(PagesScreen())..add(AirplayScreen());
super.initState();
}
這裡的..add()
是Dart語言的..語法,如果你學過程式設計模式,你一定聽說過建造者模式,簡單來說就是返回呼叫者本身。這裡list後用了..add(),還會返回list,這樣呼叫下去就可以一直向list裡增加widget元素。 最後我們呼叫了一些父類的initState()
方法。
頁面效果如下,其他頁面省略:
下一篇繼續總結!