Flutter 顶部切换导航-TabBar

2019-12-12  本文已影响0人  DDLH

目前移动开发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

待实现:底部阴影设置

上一篇下一篇

猜你喜欢

热点阅读