Flutter底部tab切換保持頁面狀態的幾種方法
- 2019 年 10 月 4 日
- 筆記
首先看一下如下影片:
通過影片我們可以看到,當通過底部tabBar將頁面在「首頁」和「分類」之間進行切換的時候,每一次進入頁面的時候該頁面的數據都會重新載入。那麼如何讓頁面保持原來的狀態,而不是每次都要重新載入刷新數據呢?有兩種方式。
第一種方式:採用IndexdStack
IndexdStack和Stack一樣,都是層布局控制項,可以在一個控制項上面放置另一個控制項,但唯一不同的是,IndexdStack在同一時刻只能顯示子控制項中的一個控制項,通過index屬性來設置顯示的控制項。
配置底部導航的核心程式碼如下:
import 'package:flutter/material.dart'; import 'package:flutter_jdshop/pages/tabs/CategoryPage.dart'; import 'package:flutter_jdshop/pages/tabs/HomePage.dart'; import 'package:flutter_jdshop/pages/tabs/ShoppingCartPage.dart'; import 'package:flutter_jdshop/pages/tabs/UserPage.dart'; class Tabs extends StatefulWidget { Tabs({Key key}) : super(key: key); _TabsState createState() => _TabsState(); } class _TabsState extends State<Tabs> { int _currentIndex = 0;//記錄當前選中哪個頁面 List<Widget> _pages = [ HomePage(), CategoryPage(), ShoppingCartPage(), UserPage() ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("JDShop")), body: this._pages[this._currentIndex], bottomNavigationBar: BottomNavigationBar( fixedColor: Colors.red,//底部導航欄按鈕選中時的顏色 type: BottomNavigationBarType.fixed,//底部導航欄的適配,當item多的時候都展示出來 currentIndex: this._currentIndex, onTap: (index){ setState(() { this._currentIndex = index; }); }, items: [ BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("首頁")), BottomNavigationBarItem(icon: Icon(Icons.category), title: Text("分類")), BottomNavigationBarItem(icon: Icon(Icons.shopping_cart), title: Text("購物車")), BottomNavigationBarItem(icon: Icon(Icons.people), title: Text("我的")) ], ), ); } }
此時還是不可以保持頁面狀態的。
這裡我們將body由
body: this._pages[this._currentIndex],
替換成
body: IndexedStack( index: this._currentIndex, children: this._pages, ),
這樣就能夠實現保持頁面狀態了,效果如下:
我們可以看到,此時,頁面的數據只在最開始進來的時候進行載入,然後就保持住這個頁面的狀態了,並不會每次進來都進行數據的載入刷新了。
使用IndexedStack來保持頁面狀態的優點就是配置簡單,但是它也有很大的缺點:IndexedStack中管理的子頁面在一開始就全部一次性載入出來了,不管有沒有顯示出來,然後通過index屬性來確定到底顯示哪一個頁面。
第二種方式:AutomaticKeepAliveClientMixin
如果所有的頁面都需要保持頁面狀態,那麼就使用indexdStack;如果有些頁面需要保持頁面狀態,有些頁面需要進來就刷新,那麼我們就需要使用AutomaticKeepAliveMixin這個類來單獨控制某個頁面的狀態。
AutomaticKeepAliveClientMixin相比IndexdStack,配置起來要複雜一些。
AutomaticKeepAliveClientMixin結合底部BottomNavigationBar來保持頁面狀態的時候,其配置步驟如下:
import 'package:flutter/material.dart'; import 'package:flutter_jdshop/pages/tabs/CategoryPage.dart'; import 'package:flutter_jdshop/pages/tabs/HomePage.dart'; import 'package:flutter_jdshop/pages/tabs/ShoppingCartPage.dart'; import 'package:flutter_jdshop/pages/tabs/UserPage.dart'; class Tabs extends StatefulWidget { Tabs({Key key}) : super(key: key); _TabsState createState() => _TabsState(); } class _TabsState extends State<Tabs> { int _currentIndex = 0;//記錄當前選中哪個頁面 //第1步,聲明PageController PageController _pageController; @override void initState() { super.initState(); //第2步,初始化PageController this._pageController = PageController(initialPage: this._currentIndex); } List<Widget> _pages = [ HomePage(), CategoryPage(), ShoppingCartPage(), UserPage() ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("JDShop")), //第3步,將body設置成PageView,並配置PageView的controller屬性 body: PageView( controller: this._pageController, children: this._pages, ), bottomNavigationBar: BottomNavigationBar( fixedColor: Colors.red,//底部導航欄按鈕選中時的顏色 type: BottomNavigationBarType.fixed,//底部導航欄的適配,當item多的時候都展示出來 currentIndex: this._currentIndex, onTap: (index){ setState(() { //第4步,設置點擊底部Tab的時候的頁面跳轉 this._currentIndex = index; this._pageController.jumpToPage(this._currentIndex); }); }, items: [ BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("首頁")), BottomNavigationBarItem(icon: Icon(Icons.category), title: Text("分類")), BottomNavigationBarItem(icon: Icon(Icons.shopping_cart), title: Text("購物車")), BottomNavigationBarItem(icon: Icon(Icons.people), title: Text("我的")) ], ), ); } }
以上前4步都是在tabs.dart中進行配置的,此時所有的頁面還是不可保持頁面狀態的。然後第5步就是在需要保持頁面狀態的頁面裡面混入AutomaticKeepAliveClientMixin類,並將wantKeepAlive方法返回為true,如下所示:
//首頁頁面 class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin{ @override bool get wantKeepAlive => true; //分類頁面 class _CategoryPageState extends State<CategoryPage> with AutomaticKeepAliveClientMixin{ @override bool get wantKeepAlive => true;
這樣,首頁頁面和分類頁面就實現了頁面狀態的保持,頁面數據只在首次進入該頁面的時候進行刷新;而其他沒有實現頁面保持的頁面在每次進入該頁面的時候,數據都會刷新。
使用AutomaticKeepAliveClientMixin這個類來保持首頁和分類頁面狀態,其效果如下所示:
以上。