顶部TabBar切换栏实现的第一种方式
在Flutter中,AppBar用于定义顶部的导航栏:
Scaffold( appBar: AppBar( title: Text("AppBarPageDemo"), ), body: Center( child: Text("AppBarDemoPageContent"), ), );
效果如下:
实际上,AppBar 这个组件有许多的属性,我们通过这些属性,可以用来定义顶部导航栏的各种样式。下面我将为你一一说明这些属性的作用:
以上几个属性是AppBar的常用属性,其使用代码如下:
Scaffold( appBar: AppBar( title: Text("AppBarPageDemo"), //标题 backgroundColor: Colors.pinkAccent, //背景颜色 //在导航栏标题左侧添加的一个组件 leading: IconButton( onPressed: () => print("menu"), icon: Icon(Icons.menu), ), //在导航栏标题右侧添加的组件组 actions: <Widget>[ IconButton( onPressed: () => print("settings"), icon: Icon(Icons.settings), ), IconButton( onPressed: () => print("edit"), icon: Icon(Icons.edit), ), IconButton( onPressed: () => print("photo"), icon: Icon(Icons.photo), ), ], centerTitle: true,//标题是否居中展示 ), body: Center( child: Text("AppBarDemoPageContent"), ), );
上述代码的展示效果如下:
接下来我们来聊聊AppBar的bottom属性。
一般而言,一个应用程序的首页底部是有一个TabBar的,用于切换各个功能页面,如下所示:
但是在有些情况下,我们需要在顶部也需要定义一个TabBar,用于切换不同的功能页面,如下面这种页面:
这个时候就需要用到AppBar的bottom属性了。也就是说,我们可以将AppBar的bottom属性值配置为一个TabBar组件,以实现在顶部添加TabBar的效果。
但是,要想给AppBar的bottom配置TabBar,那么需要在Scaffold组件的外部再包一层DefaultTabController,代码如下:
DefaultTabController( length: 2,//第1步,这里配置顶部tabbar的item个数 child: Scaffold( appBar: AppBar( //第2步,这里配置顶部tabbar bottom: TabBar( tabs: <Widget>[Tab(text: "热门"), Tab(text: "推荐")], ), title: Text("AppBarPageDemo"), backgroundColor: Colors.pinkAccent, ), //第3步,这里配置顶部TabBar每一个item所对应的页面,其元素数量需要与TabBar的item数量保持一致 body: TabBarView( children: <Widget>[ Text("热门页面"), Text("推荐页面") ], ), ), );
运行结果如下:
对于上面代码,需要以下几点:
1,DefaultTabController的length属性用于配置顶部TabBar的item数量,需要与TabBar的tabs的元素数量,以及TabBarView的children的元素数量保持一致。
2,TabBar的tabs中的Tab元素,以及TabBarView的children中的页面元素是一一对应的,对应好了之后就可以在页面中对应展示了。
3,在默认情况下,导航栏右上角有一个debug字样,如下:
如果我想把这个DEBUG字样去掉,那么可以在MaterialApp中配置debugShowCheckedModeBanner属性为false:
MaterialApp( // home: Tabs(), initialRoute: "/",//初始化的时候加载的路由 //统一处理命名路由 onGenerateRoute: prefix0.onGenerateRoute, //去掉导航栏默认的debug图标 debugShowCheckedModeBanner: false, );
再运行,我们发现DEBUG字样消失了:
我们上面讲的都是页面中只有一个AppBar的情况,这个时候如果想要加一个顶部TabBar,那么只需要配置APPBar的bottom属性即可。但是有些时候,我们会遇到不可自定义原始的AppBar的场景,而我们又想实现顶部TabBar的效果,此时我们就可以在页面中再加一个Scaffold组件,然后这样就有两个AppBar了。我们可以通过配置第二个AppBar来实现顶部TabBar的效果。
其实此时也是考验我们对AppBar以及TabBar的了解程度了。
AppBar是一个顶部导航栏,它的title属性用于配置标题,title对应的是一个组件,我们一般给title赋值为一个Text组件,但是也可根据需求给title赋值其他的组件。
AppBar的bottom属性,其对应的也是一个组件,我们一般给bottom属性赋值为TabBar组件,以实现顶部TabBar的效果。
如果在一个页面中,一个Scaffold组件内部还嵌套了另外一个Scaffold组件,并且两个Scaffold组件都配置了appbar,那么就会是如下的展示效果:
以上是两个Scaffold的appBar都配置了title,但没有配置bottom。
好,我们现在来考虑一下,在有两个Scaffold的场景下,如何实现顶部TabBar的效果。我们可以像上面所讲的,给内层的Scaffold组件的appBar配置bottom属性值为TabBar组件,但是这样的话,内层的Scaffold组件的title的位置就会有一个留空,不好看,如下所示:
为了使页面更好看,我们可以将这个顶层的TabBar赋值给内层Scaffold的appBar的title属性,前面也说了,title对应的也是一个组件。这样就能完美解决留空的问题了。代码如下:
DefaultTabController( length: 3,//顶部tabbar的元素数量 child: Scaffold( appBar: AppBar( //配置顶部tabbar title: TabBar( tabs: <Widget>[Tab(text: "热销"), Tab(text: "推荐"), Tab(text: "打折")], ), ), //这里配置顶部Tabbar所对应的页面 body: TabBarView( children: <Widget>[ Stack( ... ), Text("222"), Text("333") ], ), ), );
效果如下:
需要注意的一点是,如果我们想要通过配置AppBar的title或者bottom来实现顶部TabBar的效果,一定要在Scaffold组件外面再包一层DefaultTabController组件。
好,现在我们已经知道该如何利用AppBar和TabBar来实现顶部Tabbar的视觉效果了。在本文的最后,我们来了解一下如何个性化设置顶部TabBar导航条。
TabBar的常用属性如下:
示例代码如下:
DefaultTabController( length: 6,//这里配置顶部tabbar的item个数 child: Scaffold( appBar: AppBar( //这里配置顶部tabbar bottom: TabBar( indicatorColor: Colors.yellow, indicatorWeight: 10, indicatorSize: TabBarIndicatorSize.label, labelColor: Colors.orange, unselectedLabelColor: Colors.white, tabs: <Widget>[Tab(text: "热门"), Tab(text: "推荐"), Tab(text: "热门"), Tab(text: "推荐"), Tab(text: "热门"), Tab(text: "推荐")], ), title: Text("AppBarPageDemo"), backgroundColor: Colors.pinkAccent, ), //这里配置顶部TabBar每一个item所对应的页面,其元素数量需要与TabBar的item数量保持一致 body: TabBarView( children: <Widget>[ Text("热门页面"), Text("推荐页面"), Text("热门页面"), Text("推荐页面"), Text("热门页面"), Text("推荐页面") ], ), ), );
展示效果如下:
顶部TabBar切换栏实现的第二种方式
上面我们已经实现了顶部TabBar切换栏的UI效果,但是上面这种方式我们不好监听页面切换,当页面中有网络请求、上拉刷新下拉加载等需求的时候,我们利用第一种方式就不容易实现。所幸我们还有第二种方式,那就是利用
TabController 来实现顶部Tab切换。
步骤如下:
1,页面(TabBarControllerPage)必须是继承自StatefulWidget,也就是说,页面必须是动态页面。
2,页面的state(_TabBarControllerPageState)要实现SingleTickerProviderStateMixin类。
3,在页面的state(_TabBarControllerPageState)中要声明并初始化一个TabController实例 (_tabController)
4,在 TabBar 和 TabBarView 中都配置一下 controller 属性
5,通过_tabController.addListener监听各种事件,以处理业务逻辑。
import 'package:flutter/material.dart';
//第1步,页面必须是动态页面class TabBarControllerPage extends StatefulWidget { TabBarControllerPage({Key key}) : super(key: key);
_TabBarControllerPageState createState() => _TabBarControllerPageState();}
//第2步,通过mixins“继承”自SingleTickerProviderStateMixin类class _TabBarControllerPageState extends State<TabBarControllerPage> with SingleTickerProviderStateMixin { //第3步,声明TabController实例 TabController _tabController;
@override void initState() { super.initState(); //第4步,初始化TabController实例 _tabController = TabController( vsync: this, length: 2,//这里指定TabBar中的item数量 ); //第5步,监听TabBar的各种页面切换 _tabController.addListener((){ print(_tabController.index); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("TabBarControllerPage"), bottom: TabBar( //第6步,配置TabBar的controller controller: _tabController, tabs: <Widget>[Tab(text: "热门"), Tab(text: "推荐")], ), ), body: TabBarView( //第7步,配置TabBarView的controller controller: _tabController, children: <Widget>[Text("热门"), Text("推荐")], ), ); }}
效果如下:
第二种方式的好处是,我们可以在_tabController.addListener中监听一些Tab切换的事件,如下所示:
_tabController.addListener((){ print(_tabController.index); });
以上。