@override bool get wantKeepAlive => true;
但發現需要配合其他組件,不是隨便mixin就有用的,嘗試幾種寫法總結BottomNavigationBar+List+AutomaticKeepAliveClientMixin是沒有用的
- 首先嘗試BottomNavigationBar+List實現的頁面切換保持狀態,一般剛開始學都會這么寫:
void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) => MaterialApp( title: "demo", home: MainPage(), ); } class MainPage extends StatefulWidget { @override StatecreateState() => MainPageState(); } class MainPageState extends State{ int _currentIndex; List_pages; @override void initState() { super.initState(); _currentIndex = 0; _pages = List()..add(FirstPage("第一頁"))..add(SecondPage("第二頁"))..add(ThirdPage("第三頁")); } @override Widget build(BuildContext context) => Scaffold( body: _pages[_currentIndex], bottomNavigationBar: BottomNavigationBar( items: getItems(), currentIndex: _currentIndex, onTap: onTap, ), ); ListgetItems() { return [ BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("Home")), BottomNavigationBarItem(icon: Icon(Icons.adb), title: Text("Adb")), BottomNavigationBarItem(icon: Icon(Icons.person), title: Text("Person")) ]; } void onTap(int index) { setState(() { _currentIndex = index; }); } }
子頁面代碼,三個界面一樣:
class FirstPage extends StatefulWidget { String _title; FirstPage(this._title); @override StatecreateState() => FirstPageState(); } class FirstPageState extends Statewith AutomaticKeepAliveClientMixin{ int _count = 0; @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget._title), ), body: Center( child: Text(widget._title + ":點一下加1:$_count"), ), floatingActionButton: FloatingActionButton( heroTag: widget._title, child: Icon(Icons.add), onPressed: add), ); } void add() { setState(() { _count++; }); } }
結果無法實現保持頁面

第一個.
2.第二種BottomNavigationBar+PageView,與android的ViewPager類似,界面小改動一下,添加一個按鈕,點擊跳轉到一個新的界面

代碼如下:
void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) => MaterialApp( title: "demo", home: MainPage(), ); } class MainPage extends StatefulWidget { @override StatecreateState() => MainPageState(); } class MainPageState extends State{ int _currentIndex; List_pages; PageController _controller; @override void initState() { super.initState(); _currentIndex = 0; _pages = List() ..add(FirstPage("第一頁")) ..add(SecondPage("第二頁")) ..add(ThirdPage("第三頁")); _controller = PageController(initialPage: 0); } @override void dispose() { super.dispose(); _controller.dispose(); } @override Widget build(BuildContext context) => Scaffold( body: PageView.builder( physics: NeverScrollableScrollPhysics(),//viewPage禁止左右滑動 onPageChanged: _pageChange, controller: _controller, itemCount: _pages.length, itemBuilder: (context, index) => _pages[index]), bottomNavigationBar: BottomNavigationBar( items: getItems(), currentIndex: _currentIndex, onTap: onTap, ), ); ListgetItems() { return [ BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("Home")), BottomNavigationBarItem(icon: Icon(Icons.adb), title: Text("Adb")), BottomNavigationBarItem(icon: Icon(Icons.person), title: Text("Person")) ]; } void onTap(int index) { _controller.jumpToPage(index); } void _pageChange(int index) { setState(() { if (index != _currentIndex) { _currentIndex = index; } }); } }
子界面:
class FirstPage extends StatefulWidget { String _title; FirstPage(this._title); @override StatecreateState() => FirstPageState(); } class FirstPageState extends Statewith AutomaticKeepAliveClientMixin { int _count = 0; @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget._title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children:[ Text(widget._title + ":點一下加1:$_count"), MaterialButton( child: Text("跳轉"), color: Colors.pink, onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => NewPage()))) ], ), ), floatingActionButton: FloatingActionButton( heroTag: widget._title, child: Icon(Icons.add), onPressed: add), ); } void add() { setState(() { _count++; }); } }
需要跳轉的一個界面:
class NewPage extends StatelessWidget { @override Widget build(BuildContext context) => Scaffold( appBar: AppBar( title: Text("新的界面"), ), body: Center( child: Text("我是一個新的界面"), ), ); }

2.
猛一看效果出來了,左右切換界面沒有問題,結果跳轉新界面時又出現新問題,當第一頁跳轉新的界面再返回,再切第二、三頁發現重置了,再切回第一頁發現頁被重置了。
發生這種情況需要在重寫Widget build(BuildContext context)時調用下父類build(context)方法,局部代碼:
@override Widget build(BuildContext context) { //在這邊加上super.build(context); super.build(context); return Scaffold( appBar: AppBar( title: Text(widget._title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children:[ Text(widget._title + ":點一下加1:$_count"), MaterialButton( child: Text("跳轉"), color: Colors.pink, onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (context) => NewPage()))) ], ), ), floatingActionButton: FloatingActionButton( heroTag: widget._title, child: Icon(Icons.add), onPressed: add), ); }

第三個.
這種布局樣式網上還有一種用的比較多的是BottomNavigationBar+Stack+Offstage,這邊就不貼出來了
- 最近發現最好的實現是BottomNavigationBar+TabBarView,
BottomNavigationBar+ PageView的話如果給PageView加翻頁動畫話的第一頁直接切換第三頁,翻頁動畫不是很流暢,因為是第一頁翻到第三頁,而TabBarView切換起來就非常完美
class IndexPage extends StatefulWidget { @override _IndexPageState createState() => _IndexPageState(); } class _IndexPageState extends Statewith SingleTickerProviderStateMixin { TabController _controller; ListbottomTabs; int _currentIndex = 0; @override void initState() { super.initState(); bottomTabs = List() ..add(_buildBottomNavItem("assets/images/index_phone_unselect.png", "assets/images/index_phone_select.png", "首頁")) ..add(_buildBottomNavItem("assets/images/index_package_unselect.png", "assets/images/index_package_select.png", "包啊")) ..add(_buildBottomNavItem("assets/images/index_found_unselect.png", "assets/images/index_found_select.png", "發現")) ..add(_buildBottomNavItem("assets/images/index_person_unselect.png", "assets/images/index_person_select.png", "我的")); _controller = TabController(length: bottomTabs.length, vsync: this); } @override void dispose() { super.dispose(); _controller.dispose(); } @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: BottomNavigationBar( fixedColor: Color(0xFF333333), type: BottomNavigationBarType.fixed, currentIndex: _currentIndex, onTap: _bottomNavBarClick, items: bottomTabs), body: TabBarView( physics: NeverScrollableScrollPhysics(), //禁止滾動 controller: _controller, children: [ PhonePage(), PackagePage(), FoundPage(), PersonalPage(), ]), ); } _bottomNavBarClick(index) { setState(() { _currentIndex = index; }); _controller.animateTo(_currentIndex); } BottomNavigationBarItem _buildBottomNavItem( String icon, String activeIcon, String name) { double height = 28.0, width = 28.0; return BottomNavigationBarItem( icon: Image.asset(icon, height: height, width: width), activeIcon: Image.asset(activeIcon, height: height, width: width), title: Text(name)); } }
最后像這種多頁面使用FloatingActionButton,用它跳轉新界面是一定要設置heroTag,要不然跳轉會黑屏報錯