如何在PageView、BottomNavigationBar场景下保留页面状态避免重复请求API
解决方案
问题根因:当前实现中每次切换BottomNavigationBar索引时,旧页面会被从Widget树移除销毁,切回时重新初始化触发网络请求。
方案1:使用IndexedStack(改造成本最低)
IndexedStack会同时维护所有子Widget的状态,仅展示当前索引对应的页面,其余页面保持隐藏不销毁,适合页面数量较少的场景。
修改后的核心代码如下:
final List<Widget> _pages = const [ Page1(key: Key("Page1"),), Page2(key: Key("Page2"),), ]; int _index=0; @override Widget build(BuildContext context) { return Scaffold( // 替换原来直接取_pages[_index]的逻辑 body: IndexedStack( index: _index, children: _pages, ), bottomNavigationBar: BottomNavigationBar( currentIndex: _index, onTap: (index) => setState(() => _index = index), items: [ BottomNavigationBarItem( icon: Icon(Icons.edit_outlined,), label: "页面1" ), BottomNavigationBarItem( icon: Icon(Icons.edit_outlined,), label: "页面2" ), ]), ); }
注意:该方案会在父页面初始化时一次性加载所有子页面的生命周期方法,所有页面的网络请求会在首次进入父页面时同时触发。
方案2:PageView + AutomaticKeepAliveClientMixin(懒加载,性能更好)
如果需要页面懒加载(首次进入对应页面才触发请求),适合页面数量多或者页面初始化成本高的场景,步骤如下:
- 给所有需要保活的页面的State类混入
AutomaticKeepAliveClientMixin,重写wantKeepAlive返回true,示例:
class Page1State extends State<Page1> with AutomaticKeepAliveClientMixin { @override bool get wantKeepAlive => true; // 开启保活 @override void initState() { super.initState(); // 这里的网络请求只会在页面第一次初始化时触发一次 fetchApi(); } @override Widget build(BuildContext context) { super.build(context); // 必须调用父类方法 // 你的页面布局代码 } }
- 父页面使用
PageView承载子页面,搭配BottomNavigationBar切换:
final List<Widget> _pages = const [ Page1(key: Key("Page1"),), Page2(key: Key("Page2"),), ]; late PageController _pageController; int _index=0; @override void initState() { super.initState(); _pageController = PageController(keepPage: true); } @override void dispose() { _pageController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: PageView( controller: _pageController, physics: const NeverScrollableScrollPhysics(), // 禁止左右滑动切换,可选 children: _pages, ), bottomNavigationBar: BottomNavigationBar( currentIndex: _index, onTap: (index) { setState(() => _index = index); _pageController.jumpToPage(index); }, items: [ BottomNavigationBarItem( icon: Icon(Icons.edit_outlined,), label: "页面1" ), BottomNavigationBarItem( icon: Icon(Icons.edit_outlined,), label: "页面2" ), ]), ); }
内容的提问来源于stack exchange,提问作者balu k
相关产品推荐
相关产品推荐

