flutter底部bottomNavigationBar+PageView实现

上图

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: [
                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: [
                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: [
          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 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 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: [
                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: [
                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: [
                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: [
                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: [
                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: [
                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: [
          HomePageTab(),
          ThingsPageTab(),
          MePageTab()
        ],
        physics: NeverScrollableScrollPhysics(),
      ),
    );
  }
}

你可能感兴趣的:(flutter底部bottomNavigationBar+PageView实现)