平常開發一個 app 時,首頁通常都會有個底部導航欄,那若是底部導航欄對應的頁面有頂部導航欄,那麼應該怎麼作呢?如下是本文 demo 的效果圖:android
先直接看下 BottomNavigationBar
的用法:bash
@override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.android),
title: Text('android'),
),
BottomNavigationBarItem(
icon: Icon(Icons.favorite),
title: Text('favorite'),
),
BottomNavigationBarItem(
icon: Icon(Icons.phone),
title: Text('phone'),
),
],
onTap: (index){
setState(() {
this.selectedIndex = index;
});
},
currentIndex: selectedIndex,
),
);
}
複製代碼
在 Scaffold
中有個 bottomNavigationBar
屬性就是專門爲底部導航欄提供的,BottomNavigationBar
有幾個必須實現的屬性,首先 items
,你想要有幾個導航欄條目就放幾個 BottomNavigationBarItem
部件便可。你還須要實現 onTap
屬性,在點擊條目的時候改變選中的索引 selectedIndex
,這個 selectedIndex
用於 currentIndex
屬性,同時也會定位每一個導航欄條目對應的頁面。從點擊事件中也能夠看出,底部導航欄所屬的頁面必須是 StatefulWidget
,由於 selectedIndex
是可變的。app
完成底部導航欄的部件後,接下來須要建立每一個導航欄 item
對應的頁面了,這個其實直接在 Scaffold
中的 body
定義便可:less
final List<Widget> bottomBarViews = [
FirstBarView(),
SecondBarView(),
ThirdBarView(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: bottomBarViews[selectedIndex],
);
}
複製代碼
bottomBarViews
裏是一系列你任意定義的頁面,數量和導航欄條目數量一致。ide
頂部導航欄用 TabBar
實現,官方文檔和不少文章都會用下面這種方式來實現:佈局
@override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: choices.length,
child: Scaffold(
appBar: AppBar(
title: const Text('Tabbed AppBar'),
bottom: TabBar(
isScrollable: true,
tabs: choices.map((Choice choice) {
return Tab(
text: choice.title,
icon: Icon(choice.icon),
);
}).toList(),
),
),
body: TabBarView(
children: choices.map((Choice choice) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ChoiceCard(choice: choice),
);
}).toList(),
),
),
),
);
}
複製代碼
DefaultTabController
是 Flutter 提供的默認同步 TabBar
和 TabBarView
狀態的部件,通常都會把 TabBar
寫到 AppBar
的 bottom
屬性中,而後在 Scaffold
的 body
屬性中放入 TabBarView
。這兩個部件也是比較好理解,每一個頂部導航欄 item
對應一張頁面。可是這樣和底部導航欄就衝突了,兩個頁面列表都是放在 Scaffold
的 body
屬性,那麼如何調整呢?ui
我在底部導航欄的第三個頁面 ThirdBarView
中加入頂部導航欄:this
class ThirdBarViewState extends State<ThirdBarView> with SingleTickerProviderStateMixin{
List tabs = ["新聞", "歷史", "圖片"];
TabController tabController;
@override
void initState() {
super.initState();
tabController = TabController(length: tabs.length, vsync: this);
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TabBar(
tabs: tabs.map((text) => Tab(text: text)).toList(),
controller: tabController,
labelColor: Colors.blue,
indicatorColor: Colors.pink,
),
Expanded(
child: TabBarView(
controller: tabController,
children: tabs.map((text){
return Center(
child: Text(text),
);
}).toList(),
),
),
],
);
}
}
複製代碼
首先由於沒有使用 DefaultTabController
,咱們須要聲明一個 TabController
對象,能夠經過這個對象來控制 TabBar
和 TabBarView
同步。而後就按照佈局的方式把這兩個部件放到 Column
中,TabBarView
外面須要包一層 Expanded
來佔據剩餘的空間。spa
最後貼出全部的代碼:code
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
title: 'tabbar',
home: TableBarDemo(),
));
class TableBarDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return TableBarState();
}
}
class TableBarState extends State<TableBarDemo> {
int selectedIndex = 0;
final List<Widget> bottomBarViews = [
FirstBarView(),
SecondBarView(),
ThirdBarView(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TabBar'),
),
body: bottomBarViews[selectedIndex],
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.android),
title: Text('android'),
),
BottomNavigationBarItem(
icon: Icon(Icons.favorite),
title: Text('favorite'),
),
BottomNavigationBarItem(
icon: Icon(Icons.phone),
title: Text('phone'),
),
],
onTap: (index){
setState(() {
this.selectedIndex = index;
});
},
currentIndex: selectedIndex,
),
);
}
}
class FirstBarView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('android'),
);
}
}
class SecondBarView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('favorite'),
);
}
}
class ThirdBarView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return ThirdBarViewState();
}
}
class ThirdBarViewState extends State<ThirdBarView> with SingleTickerProviderStateMixin{
List tabs = ["新聞", "歷史", "圖片"];
TabController tabController;
@override
void initState() {
super.initState();
tabController = TabController(length: tabs.length, vsync: this);
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TabBar(
tabs: tabs.map((text) => Tab(text: text)).toList(),
controller: tabController,
labelColor: Colors.blue,
indicatorColor: Colors.pink,
),
Expanded(
child: TabBarView(
controller: tabController,
children: tabs.map((text){
return Center(
child: Text(text),
);
}).toList(),
),
),
],
);
}
}
複製代碼