一,概述
TabBar,是材料設計(Material design)中很常用的一種橫向標簽頁。在Android原生開發中,我們常用ViewPage或者一些常用的標簽頁開源庫,來實現並行界面的橫向滑動展示,在iOS原生開發中我們可以基於UICollectionView/UIButton來封裝實現這一功能,在Flutter的世界中,TabBar是被定義在Material Component中,所以他的使用需要在MaterialApp中。通常,我們會在AppBar的底部部分結合TabBarView來使用TabBar。
二,Tab關鍵元素
- TabController
這是Tab頁的控制器,用於定義Tab標簽和內容頁的坐標,還可配置標簽頁的切換動畫效果等。
TabController一般放入有狀態控件中使用,以適應標簽頁數量和內容有動態變化的場景,如果標簽頁在APP中是靜態固定的格局,則可以在無狀態控件中加入簡易版的DefaultTabController以提高運行效率,畢竟無狀態控件要比有狀態控件更省資源,運行效率更快。
- TabBar
Tab頁的Title控件,切換Tab頁的入口,一般放到AppBar控件下使用,內部有*Title屬性。其子元素按水平橫向排列布局,如果需要縱向排列,請使用Column或ListView控件包裝一下。子元素為Tab類型的數組。
- TabBarView
Tab頁的內容容器,其內放置Tab頁的主體內容。子元素可以是多個各種類型的控件。
三,構造函數
- TabController
- DefalutTabController
const DefaultTabController({ Key key, @required this.length, this.initialIndex = 0, @required this.child, }) : assert(initialIndex != null), assert(length >= 0), assert(initialIndex >= 0 && initialIndex < length), super(key: key);
- TabController
TabController({ int initialIndex = 0, @required this.length, @required TickerProvider vsync }) : assert(length != null && length >= 0), assert(initialIndex != null && initialIndex >= 0 && (length == 0 || initialIndex < length)), _index = initialIndex, _previousIndex = initialIndex, _animationController = AnimationController.unbounded( value: initialIndex.toDouble(), vsync: vsync, );
- DefalutTabController
- TabBar
/** const TabBar({ Key key, @required this.tabs,//顯示的標簽內容,一般使用Tab對象,也可以是其他的Widget this.controller,//TabController對象 this.isScrollable = false,//是否可滾動 this.indicatorColor,//指示器顏色 this.indicatorWeight = 2.0,//指示器高度 this.indicatorPadding = EdgeInsets.zero,//底部指示器的Padding this.indicator,//指示器decoration,例如邊框等 this.indicatorSize,//指示器大小計算方式,TabBarIndicatorSize.label跟文字等寬,TabBarIndicatorSize.tab跟每個tab等寬 this.labelColor,//選中label顏色 this.labelStyle,//選中label的Style this.labelPadding,//每個label的padding值 this.unselectedLabelColor,//未選中label顏色 this.unselectedLabelStyle,//未選中label的Style }) : assert(tabs != null), assert(isScrollable != null), assert(indicator != null || (indicatorWeight != null && indicatorWeight > 0.0)), assert(indicator != null || (indicatorPadding != null)), super(key: key); */
- Tab
const Tab({ Key key, this.text, this.icon, this.child, }) : assert(text != null || child != null || icon != null), assert(!(text != null && null != child)), // TODO(goderbauer): https://github.com/dart-lang/sdk/issues/34180 super(key: key);
- Tab
- TabBarView
const TabBarView({ Key key, @required this.children, //Tab頁內容頁組件數組集合 this.controller, //TabController對象 this.physics, this.dragStartBehavior = DragStartBehavior.start, }) : assert(children != null), assert(dragStartBehavior != null), super(key: key);
四,創建標簽欄
- 1.創建TabController
- 使用默認的DefaultController
/**2.創建Tabbar */ @override Widget build(BuildContext context) { // TODO: implement build return new DefaultTabController( length: myTabs.length, child: new Scaffold( //AppBar appBar:new AppBar( title: new Text('頂部標簽欄'), bottom: new TabBar( tabs: myTabs, //標簽數組 indicatorColor: Colors.blue,//指示器的顏色 isScrollable: true,//是否滑動 ), ) , /**3.綁定Tabbar 和 TabBarView */ //body body: new TabBarView( children: myTabs.map((Tab tab){ return new Center( child: new Text(tab.text)); }).toList(), ), ), ); }
- 使用自定義的TabController的
class TabBarDemoState extends State<TabBarDemo> with SingleTickerProviderStateMixin { TabController _tabController; //定義tabcontroller變量 @override void dispose() { _tabController.dispose(); //銷毀 super.dispose(); } void initState() { super.initState(); _tabController = new TabController(vsync: this, length: 3); //創建 } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('頂部tab切換'), bottom: new TabBar( tabs: <Widget>[ new Tab( icon: new Icon(Icons.directions_bike), ), new Tab( icon: new Icon(Icons.directions_boat), ), new Tab( icon: new Icon(Icons.directions_bus), ), ], controller: _tabController, //tabbar與自定義的tabcontroller綁定 ), ), body: new TabBarView( controller: _tabController, //tabbarView與 自定義的tabController綁定 children: <Widget>[ new Center(child: new Text('自行車')), new Center(child: new Text('船')), new Center(child: new Text('巴士')), ], ), ); }
- 使用默認的DefaultController
- 2.構建Tab數據/TabBarView數據
/**1. 創建Tab數據 */ final List<Tab> myTabs = <Tab>[ new Tab(icon: new Icon(Icons.home), text:'首頁', ), new Tab( icon: new Icon(Icons.message), text:'個人信息', ), new Tab( icon: new Icon(Icons.camera), text:'朋友圈', ), new Tab( icon: new Icon(Icons.access_alarm), text: '鬧鍾', ) ];
- 3. 創建Tabbar
appBar:new AppBar( title: new Text('頂部標簽欄'), bottom: new TabBar( tabs: myTabs, //標簽數組 indicatorColor: Colors.blue,//指示器的顏色 isScrollable: true,//是否滑動 ), )
- 4.綁定TabBar 和 TabBarView
/**3.綁定Tabbar 和 TabBarView */ //body body: new TabBarView( children: myTabs.map((Tab tab){ return new Center( child: new Text(tab.text)); }).toList(), ),
- 5.全部代碼
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // TODO: implement build return new MaterialApp( title: '頂部標簽欄', theme: new ThemeData( primaryColor: Colors.red ), home: new App(), ); } } class App extends StatelessWidget { /**1. 創建Tab數據 */ final List<Tab> myTabs = <Tab>[ new Tab(icon: new Icon(Icons.home), text:'首頁', ), new Tab( icon: new Icon(Icons.message), text:'個人信息', ), new Tab( icon: new Icon(Icons.camera), text:'朋友圈', ), new Tab( icon: new Icon(Icons.access_alarm), text: '鬧鍾', ) ]; /**2.創建Tabbar */ @override Widget build(BuildContext context) { // TODO: implement build return new DefaultTabController( length: myTabs.length, child: new Scaffold( //AppBar appBar:new AppBar( title: new Text('頂部標簽欄'), bottom: new TabBar( tabs: myTabs, //綁定標簽數組 indicatorColor: Colors.blue,//指示器的顏色 isScrollable: true,//是否滑動 ), ) , /**3.綁定Tabbar 和 TabBarView */ //body body: new TabBarView( children: myTabs.map((Tab tab){ return new Center( child: new Text(tab.text)); }).toList(), ), ), ); } }
五,總結
TabBarView和TabBar都有一個TabController的參數,TabbarView和TabBar就是由TabController來控制同步,點擊某個Tab后,要同步顯示對應的TabBarView,創建TabController有兩種方式:
- 第一種:使用系統自帶的DefaultTabController,在Scaffold套一層DefaultTabController,這種方式TabBarView會自動查找這個tabController。
@override Widget build(BuildContext context) { return new DefaultTabController(); }
- 第二種是自己定義一個TabController,實現SingleTickerProviderStateMixin
參考上面“使用自定tabcontroller代碼”