flutter底部bottomNavigationBar+PageView实现 我会带着你远行 2021-10-01 11:16 434阅读 0赞 # 上图 # ![11172442-9645f7163a7b2a64.png][] AEB9E959-B62A-405E-BA60-DD9759B0A1A9.png # 需要实现的功能: # * 底部tab(可自定义样式)点击切换中间内容 * 不要一般的tab切换时相隔几个页面会缓慢过渡的问题(一般bottomNavigationBar+TabBarView实现会存在的问题) * 中间内容不可滑动 * 切换页面时页面不重建 # 实现过程 # 1. 一个Scaffold+bottomNavigationBar+pageView Tab(child: _nowIndex==0?Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset("images/nav_home_h.png",width: 25,height: 25,fit: BoxFit.fill,), Text("首页",style: TextStyle(decoration: TextDecoration.none,color: Colors.blue,fontSize: 14),) ], ):Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset("images/nav_home.png",width: 25,height: 25,fit: BoxFit.fill,), Text("首页",style: TextStyle(decoration: TextDecoration.none,color: Colors.grey,fontSize: 14),) ], ),) 可自定义tabbar样式就需要使用tab的child属性,使用\_nowIndex记录当前页面切换到那一个页面了,然后使用三目运算符针对不同的页面赋值不同的child,flutter中都是一个个widget,所以tab的样式可以随心所欲,这里我只是实现了与使用tab的text和icon属性一样的效果 2.一般使用bottomNavigationBar+TabBarView假设我们有4个页面,当前我们再第4个页面,然后我们点击tab切换到第一个页面,会出现一个效果就是一次从3切换到2再切换到1,虽然这个过程是很快的,但是也丢失了android原生的fragment切换效果,所以我们这里采用pageView来实现中间页面的展示。 body: PageView( controller: _pageController, children: <Widget>[ HomePageTab(), ThingsPageTab(), MePageTab() ], // 这里很重要就是需要实现的第三个要求 physics: NeverScrollableScrollPhysics(), ), 然后就是tabbar和pageview的控制器了,这一步就是将点击底部,同时也切换page连接起来。 TabController _tabController; PageController _pageController; var _nowIndex =0; @override void initState() { // TODO: implement initState super.initState(); //创建页面的控制器 _pageController = PageController(); //创建底部tab的控制器,并且设置tab改变的监听 _tabController = TabController(length: 3, vsync: this)..addListener((){ // 当tab改变时,使用页面的controller跳转到指定的页面,这样就不会有依次切换的效果 _pageController.jumpToPage(_tabController.index); // 使用setstate 设置数据记录当前切换到哪一个页面,自动重绘底部tab(响应式) setState(() { _nowIndex = _tabController.index; }); }); } 3.这时候pageview还是能滑动切换的,如果需要在滑动切换后同时切换底部tab可以使用pageView的onChange属性,在onChange时同时响应式设置 \_nowIndex的值,就可以达到同步,但是这里我选择直接禁用pageView的滑动,就是使用pageview的''physics: NeverScrollableScrollPhysics(),''这个属性就可以设置不可以滑动切换,请看第2点的第一段代码 4.接下来就是点击底部tab切换时,每一次页面都会新建和销毁,就好像android原生的fragment的replace方法,在android原生中我们使用hide和show的方式来防止重建,那么我们再flutter中如何实现呢,就是在每一个子页面的state类后面混合AutomaticKeepAliveClientMixin class ThingsPageTab extends StatefulWidget { @override _ThingsPageTabState createState() => _ThingsPageTabState(); } // 1.防止重建加with AutomaticKeepAliveClientMixin class _ThingsPageTabState extends State<ThingsPageTab> with AutomaticKeepAliveClientMixin{ @override Widget build(BuildContext context) { return Text("things",style: TextStyle(fontSize: 50),); } // 2.防止重建必须要的实现 返回true @override // TODO: implement wantKeepAlive bool get wantKeepAlive => true; } # 完结 # * 这样整个功能就实现了,贴主页完整的代码 import 'package:flutter/material.dart'; import 'package:jygonline/ui/fragment/home_page.dart'; import 'package:jygonline/ui/fragment/things_page.dart'; import 'package:jygonline/ui/fragment/me_page.dart'; class MainPage extends StatefulWidget { @override _MainPageState createState() => _MainPageState(); } class _MainPageState extends State<MainPage> with SingleTickerProviderStateMixin{ TabController _tabController; PageController _pageController; var _nowIndex =0; @override void initState() { // TODO: implement initState super.initState(); _pageController = PageController(); _tabController = TabController(length: 3, vsync: this)..addListener((){ _pageController.jumpToPage(_tabController.index); setState(() { _nowIndex = _tabController.index; }); }); } @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: Container( height: 60, color: Colors.white, child: TabBar(tabs: [ Tab(child: _nowIndex==0?Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset("images/nav_home_h.png",width: 25,height: 25,fit: BoxFit.fill,), Text("首页",style: TextStyle(decoration: TextDecoration.none,color: Colors.blue,fontSize: 14),) ], ):Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset("images/nav_home.png",width: 25,height: 25,fit: BoxFit.fill,), Text("首页",style: TextStyle(decoration: TextDecoration.none,color: Colors.grey,fontSize: 14),) ], ),), Tab(child: _nowIndex==1?Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset("images/nav_bs_h.png",width: 25,height: 25,fit: BoxFit.fill,), Text("办事",style: TextStyle(decoration: TextDecoration.none,color: Colors.blue,fontSize: 14),) ], ):Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset("images/nav_bs.png",width: 25,height: 25,fit: BoxFit.fill,), Text("办事",style: TextStyle(decoration: TextDecoration.none,color: Colors.grey,fontSize: 14),) ], ),), Tab(child: _nowIndex==2?Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset("images/nav_my_h.png",width: 25,height: 25,fit: BoxFit.fill,), Text("个人中心",style: TextStyle(decoration: TextDecoration.none,color: Colors.blue,fontSize: 14),) ], ):Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ Image.asset("images/nav_my.png",width: 25,height: 25,fit: BoxFit.fill,), Text("个人中心",style: TextStyle(decoration: TextDecoration.none,color: Colors.grey,fontSize: 14),) ], ),), ], controller: _tabController, indicatorColor: Colors.white, isScrollable: false, indicatorWeight: 0.01, ), ), body: PageView( controller: _pageController, children: <Widget>[ HomePageTab(), ThingsPageTab(), MePageTab() ], physics: NeverScrollableScrollPhysics(), ), ); } } [11172442-9645f7163a7b2a64.png]: /images/20210825/e7c00567ba3147d496c1f41c94f73f5f.png
还没有评论,来说两句吧...