目前移动开发tab切换是一个很通用的功能,Flutter 通过Material 库提供了很方便的API来使用tab切换。
下面我们通过“bottom”属性来添加一个导航栏底部Tab按钮组:
image.pngMaterial组件库中提供了一个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
待实现:底部阴影设置
网友评论