Flutter BottomNavigationBar切换页面被重置问题(保存状态)
开始尝试用flutter开发,flutter版本1.0,写类似微信底部tab切换界面时发现界面老被重置,网上找了一圈说保持状态需要子页面mixin AutomaticKeepAliveClientMixin,然后重写
@override bool get wantKeepAlive => true;
但发现需要配合其他组件,不是随便mixin就有用的,尝试几种写法总结BottomNavigationBar+List<Widget>+AutomaticKeepAliveClientMixin是没有用的
- 首先尝试BottomNavigationBar+List<Widget>实现的页面切换保持状态,一般刚开始学都会这么写:
void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) => MaterialApp( title: "demo", home: MainPage(), ); } class MainPage extends StatefulWidget { @override State<StatefulWidget> createState() => MainPageState(); } class MainPageState extends State<MainPage> { int _currentIndex; List<Widget> _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, ), ); List<BottomNavigationBarItem> getItems() { 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 State<StatefulWidget> createState() => FirstPageState(); } class FirstPageState extends State<FirstPage> with 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 State<StatefulWidget> createState() => MainPageState(); } class MainPageState extends State<MainPage> { int _currentIndex; List<Widget> _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, ), ); List<BottomNavigationBarItem> getItems() { 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) { if (index != _currentIndex) { setState(() { _currentIndex = index; }); } } }
子界面:
class FirstPage extends StatefulWidget { String _title; FirstPage(this._title); @override State<StatefulWidget> createState() => FirstPageState(); } class FirstPageState extends State<FirstPage> with 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: <Widget>[ 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("我是一个新的界面"), ), ); }
猛一看效果出来了,左右切换界面没有问题,结果跳转新界面时又出现新问题,当第一页跳转新的界面再返回,再切第二、三页发现重置了,再切回第一页发现页被重置了。
发生这种情况需要在重写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: <Widget>[ 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+IndexedStack( ),这边就不贴出来了
- 经过长期测试BottomNavigationBar+TabBarView方案行不通,后期会遇到其他问题,目前最好用还是viewpage和IndexedStack。
最后像这种多页面使用FloatingActionButton,用它跳转新界面是一定要设置heroTag,要不然跳转会黑屏报错
作者:简wen
链接:https://www.jianshu.com/p/87e545b889cd
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库