美文网首页
Flutter 顶部切换导航-TabBar

Flutter 顶部切换导航-TabBar

作者: DDLH | 来源:发表于2019-12-12 20:20 被阅读0次

    目前移动开发tab切换是一个很通用的功能,Flutter 通过Material 库提供了很方便的API来使用tab切换。

    下面我们通过“bottom”属性来添加一个导航栏底部Tab按钮组:

    image.png

    Material组件库中提供了一个TabBar组件,它可以快速生成Tab菜单,下面是上图对应的源码:

    class _ScaffoldRouteState extends State<ScaffoldRoute>
        with SingleTickerProviderStateMixin {
      TabController _tabController; //需要定义一个Controller
      List tabs = ["新闻", "历史", "图片"];
    
      @override
      void initState() {
        super.initState();
        // 创建Controller
        _tabController = TabController(length: tabs.length, vsync: this);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            //导航栏
            title: Text("App Name"),
            leading: Builder(builder: (context) {
              return IconButton(
                icon: Icon(Icons.dashboard, color: Colors.white), //自定义图标
                onPressed: () {
                  // 打开抽屉菜单
                  Scaffold.of(context).openDrawer();
                },
              );
            }),
            bottom: TabBar(
                //生成Tab菜单
                controller: _tabController,
                tabs: tabs.map((e) => Tab(text: e)).toList()),
          ),
          // ...
        );
      }
    }
    

    上面代码首先创建了一个TabController ,它是用于控制/监听Tab菜单切换的。接下来通过TabBar生成了一个底部菜单栏,TabBar的tabs属性接受一个Widget数组,表示每一个Tab子菜单,我们可以自定义,也可以像示例中一样直接使用Tab 组件,它是Material组件库提供的Material风格的Tab菜单。

    TabBarView

    通过TabBar我们只能生成一个静态的菜单,真正的Tab页还没有实现。由于Tab菜单和Tab页的切换需要同步,我们需要通过TabController去监听Tab菜单的切换去切换Tab页,代码如:

    _tabController.addListener((){  
      switch(_tabController.index){
        case 1: ...;
        case 2: ... ;   
      }
    });
    

    如果我们Tab页可以滑动切换的话,还需要在滑动过程中更新TabBar指示器的偏移!显然,要手动处理这些是很麻烦的,为此,Material库提供了一个TabBarView组件,通过它不仅可以轻松的实现Tab页,而且可以非常容易的配合TabBar来实现同步切换和滑动状态同步,示例如下:

    class ScaffoldRoute extends StatefulWidget {
      @override
      _ScaffoldRouteState createState() => _ScaffoldRouteState();
    }
    
    class _ScaffoldRouteState extends State<ScaffoldRoute>
        with SingleTickerProviderStateMixin {
      TabController _tabController; //需要定义一个Controller
      List tabs = ["新闻", "历史", "图片"];
    
      @override
      void initState() {
        super.initState();
        // 创建Controller
        _tabController = TabController(length: tabs.length, vsync: this);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            //导航栏
            // ... 省略无关代码
            bottom: TabBar(
                //生成Tab菜单
                controller: _tabController,
                tabs: tabs.map((e) => Tab(text: e)).toList()),
          ),
          body: TabBarView(
            controller: _tabController,
            children: tabs.map((e) {
              //创建3个Tab页
              return Container(
                alignment: Alignment.center,
                child: Text(e, textScaleFactor: 3),
              );
            }).toList(),
          ),
        );
      }
    }
    
    image.png

    现在,无论是点击导航栏Tab菜单还是在页面上左右滑动,Tab页面都会切换,并且Tab菜单的状态和Tab页面始终保持同步!那它们是如何实现同步的呢?细心的读者可能已经发现,上例中TabBar和TabBarView的controller是同一个!正是如此,TabBar和TabBarView正是通过同一个controller来实现菜单切换和滑动状态同步的

    自定义TabBar

    TabBar 常见属性:

    属性 描述
    tabs 显示的标签内容,一般使用 Tab 对象,也可以是其他 的 Widget
    controller TabController对象
    isScrollable 是否可滚动
    indicatorColor 指示器颜色
    indicatorWeight 指示器高度
    indicatorPadding 底部指示器的 Padding
    indicator 指示器 decoration,例如边框等
    indicatorSize 指示器大小计算方式,TabBarIndicatorSize.label 跟文 字等宽,TabBarIndicatorSize.tab 跟每个 tab 等宽
    labelColor 选中 label 颜色
    labelStyle 选中 label 的 Style
    labelPadding 每个 label 的 padding 值
    unselectedLabelColor 未选中 label 颜色
    unselectedLabelStyle 未选中 label 的 Style
    // 主代码更改
    Scaffold(
      appBar: AppBar(
        //导航栏
        ...
        elevation: 0, // 去掉导航栏阴影
      ),
      body: ChildItemIndex('TabBar'), //自定义TabBar
    )
    
    
    
    //自定义TabBar
    class ChildItemIndex extends StatefulWidget {
      String _title;
    
      ChildItemIndex(this._title);
      @override
      _ChildItemIndexState createState() => _ChildItemIndexState();
    }
    
    class _ChildItemIndexState extends State<ChildItemIndex>
        with SingleTickerProviderStateMixin {
      TabController _tabController; //需要定义一个Controller
      List tabs = ["新闻", "历史", "图片"];
    
      @override
      void initState() {
        super.initState();
        // 创建Controller
        _tabController = TabController(length: tabs.length, vsync: this);
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          // 这里设置tab的背景色
          color: Colors.blue,
          child: new TabBar(
            indicatorColor: Colors.white, //指示器颜色
            labelColor: Colors.white, //选中 label 颜色
            unselectedLabelColor: Colors.white70, //未选中 label 颜色
            indicatorSize: TabBarIndicatorSize
                .tab, //指示器大小计算方式,TabBarIndicatorSize.label 跟文 字等宽,TabBarIndicatorSize.tab 跟每个 tab 等宽
            tabs: <Widget>[
              new Tab(
                icon: new Icon(Icons.directions_bike),
              ),
              new Tab(
                icon: new Icon(Icons.directions_boat),
              ),
              new Tab(
                icon: new Icon(Icons.directions_bus),
              ),
            ],
            controller: _tabController,
          ),
        );
      }
    }
    

    最终实现效果如图:


    image.png

    待实现:底部阴影设置

    相关文章

      网友评论

          本文标题:Flutter 顶部切换导航-TabBar

          本文链接:https://www.haomeiwen.com/subject/qjlogctx.html