使用 Flutter 實現帶底部導航欄的 APP 主頁面,根節點使用 Scaffold,再配置 bottomNavigationBar 設置點擊事件通過調用 setState()
方法在 build 返回不同的頁面即可。但運行後會發現,點擊切換頁面後之前的頁面狀態無法保持,切換頁面後再切回之前的頁面,頁面顯示的數據會重繪爲初始狀態。這是因爲 flutter 頁面默認情況下每次都是返回的一個新的對象,重新繪製再界面的,不做任何處理的情況下自然不能保留數據。要解決這個問題,有下面的三種實現方式:
一、Stack + OffStage + TickerMode 堆疊
簡單粗暴,跟 Android 開發中在 FrameLayout 中堆疊 View,再根據需要控制部分 View 的顯示於隱藏,在構建頁面時 body 直接返回一個 Stack 對象,子 widget 即爲要顯示的所有頁面:
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Stack(children: <Widget>[
_makePage(0),
_makePage(1),
_makePage(2),
_makePage(3),
]),
bottomNavigationBar: _getNavigationBar(),
);
/*
* Stack 方式創建頁面
*/
Widget _makePage(int index) {
return Offstage(
offstage: this._currentIndex != index,
child: TickerMode(enabled: this._currentIndex == index, child: _pageList[index]));
}
通過 TickerMode 的 enabled 來控制頁面是否顯示,當頁面的 index 爲當期選中的 index 時顯示否則隱藏。
二、IndexedStack 控制頁面的顯示
類似 Android 中 FragementTransManager 控制 fragement 的顯示隱藏,這與第一種方式沒有太大本質上的區別,只不過是顯示判斷邏輯交給 IndexedStack 內部自動完成,與第一種方式相比代碼量會少很多
// IndexStack 方式
return new Scaffold(
body: IndexedStack(index: _currentIndex, children: _pageList),
bottomNavigationBar: _getNavigationBar(),
);
三、PageView
PageView 類似於 Android 中的 ViewPager 支持,頁面之間的滑動切換。這種方式需要每一個要保持狀態的 Widget 狀態管理類實現 AutomaticKeepAliveClientMixin<Widget>
,並且 wangKeepAlive
返回 true。僞代碼如下:
class WidgetState extends State<Widget>
with AutomaticKeepAliveClientMixin<Widget> {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Widget;
}
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
這個樣 PageView 在切換時 flutter 內部就會知道你想要保持對應頁面的狀態,在頁面切換時會將數據保留下來。這種方式是支持滑動切換頁面的
總結
不需要支持左右滑動切換頁面直接使用第二種方式實現導航欄效果,需要滑動切換頁面效果則使用第三種方式。不推薦使用第一種方式實現此功能
Demo