TabBar
还有TabBarView
都是谷歌flutter官方组件库——Material组件库提供的组件,其中TabBar
用于导航切换,TabBarView
则是配合其切换显示的对应的视图。我在使用它们的时候也是遇到了不少问题,所以想通过这篇文章总结一下它们的几种使用方式,以及如何实现TabBar每次切换页面不重载。
一、TabBar配合TabBarView
-
实现效果:点击tab滑动切换视图或者是手势左侧滑动切换视图。效果如下所示:
-
两种实现方式:默认控制器和自定义控制器
tabBar
与tabBarView
的联动,需要通过控制器controller
实现,其中tabBar
还有tabBarView
构造函数都有controller
这个属性(具体的参数如下所示),通过给这个属性设置controller
我们就可以控制它们的联动。//TabBar参数: const TabBar({ Key key, @required this.tabs,//子标签 this.controller,//控制器 this.isScrollable = false,//能否滑动,false:tab宽度则等比,true:tab宽度则包裹item this.indicatorColor,//指示器颜色 this.indicatorWeight = 2.0, this.indicatorPadding = EdgeInsets.zero, this.indicator, this.indicatorSize,//TabBarIndicatorSize.label:indicator与文字同宽,TabBarIndicatorSize.tab:与tab同宽 this.labelColor,//选中标签颜色 this.labelStyle,//选中标签样式 this.labelPadding, this.unselectedLabelColor,//未选中标签颜色 this.unselectedLabelStyle, this.dragStartBehavior = DragStartBehavior.down, this.onTap,//点击事件 }) //TabBarView参数 const TabBarView({ Key key, @required this.children,//子widget this.controller,//控制器 this.physics, this.dragStartBehavior = DragStartBehavior.down, })
-
默认控制实现:
系统提供了一个
DefaultTabController
,只需要把TabBar
和TabBarView
包裹起来就能实现联动,不需要额外去监听什么。DefaultTabController
参数如下所示:const DefaultTabController({ Key key, @required this.length, this.initialIndex = 0, @required this.child, })
实现例子:如下:只需要把TabBar与TabBarView包裹在DefaultTabControlle就可以了
...//省略无关代码 List tabs = ["新闻", "历史", "图片"]; return new DefaultTabController( length: tabs.length, child: new Scaffold( appBar: AppBar( ... //省略无关代码 bottom: TabBar( //生成Tab菜单 tabs: tabs.map((e) => Tab(text: e)).toList() ), ), ... //省略无关代码 body: new TabBarView( children: tabs.map((e) { //分别创建对应的Tab页面 return Container( alignment: Alignment.center, child: Text(e, textScaleFactor: 5), ); }).toList(), ), ), );
-
自定义控制器实现
-
首先添加
SingleTickerProviderStateMixin
class _MyStartState extends State<MyStart> with SingleTickerProviderStateMixin { }
-
定义我们的
Controller
并初始化class _MyStartState extends State<MyStart> with SingleTickerProviderStateMixin { TabController controller;//tab控制器 int _currentIndex = 0; //选中下标 @override void initState() { super.initState(); //初始化controller并添加监听 controller = TabController(length: _datas.length, vsync: this); controller.addListener(() => _onTabChanged()); } } _onTabChanged() { if (_controller.index.toDouble() == _controller.animation.value) { //赋值 并更新数据 this.setState(() { _currentIndex = controller.index; }); getDetail(); } }
-
重新配置
TabBar
和TabBarView
return new Scaffold( appBar: new TabBar( controller: controller,//关键一步,其他一样:控制器 ... ), body: new TabBarView( controller: controller,//关键一步,其他一样:控制器 ... ), );
-
补充:
注意我们初始化控制器的时候加了下面的代码,目的是为了监听tab的切换
controller.addListener(() => _onTabChanged());
由于我们需要在tab切换的时候做判断,执行一些业务逻辑,比如获取新的数据。所以我们需要监听它的变化。如果只是单纯切换视图配置号controller就可以了。
-
-
二、TabBar每次切换页面不重载
tab切换页面实现持久化状态:每次tab切换页面页面的状态都会还原,这里我们使用
AutomaticKeepAliveClientMixin
类,因为通过控制它可以根据你需要的页面进行配置要不要二次切换页面后就保持状态,如果需要就设置,如果不需要是要每次进入都重新刷新一遍就不要配置。
-
tabBar
与tabBarView
配置:
import 'package:flutter/material.dart';
import 'package:flutter_jdshop/pages/tabs/CategoryPage.dart';
import 'package:flutter_jdshop/pages/tabs/HomePage.dart';
import 'package:flutter_jdshop/pages/tabs/ShoppingCartPage.dart';
import 'package:flutter_jdshop/pages/tabs/UserPage.dart';
class Tabs extends StatefulWidget {
Tabs({Key key}) : super(key: key);
_TabsState createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex = 0;//记录当前选中哪个页面
//第1步,声明PageController
PageController _pageController;
@override
void initState() {
super.initState();
//第2步,初始化`PageController`
this._pageController = PageController(initialPage: this._currentIndex);
}
List<Widget> _pages = [
HomePage(),
CategoryPage(),
ShoppingCartPage(),
UserPage()
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("JDShop")),
//第3步,将body设置成PageView,并配置PageView的controller属性
body: PageView(
controller: this._pageController,
children: this._pages,
),
bottomNavigationBar: BottomNavigationBar(
fixedColor: Colors.red,//底部导航栏按钮选中时的颜色
type: BottomNavigationBarType.fixed,//底部导航栏的适配,当item多的时候都展示出来
currentIndex: this._currentIndex,
onTap: (index){
setState(() {
//第4步,设置点击底部Tab的时候的页面跳转
this._currentIndex = index;
this._pageController.jumpToPage(this._currentIndex);
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("首页")),
BottomNavigationBarItem(icon: Icon(Icons.category), title: Text("分类")),
BottomNavigationBarItem(icon: Icon(Icons.shopping_cart), title: Text("购物车")),
BottomNavigationBarItem(icon: Icon(Icons.people), title: Text("我的"))
],
),
);
}
}
-
对应的
tabBarview
页面配置:需要保持页面状态的页面里面混入
AutomaticKeepAliveClientMixin
类,并将wantKeepAlive
方法返回为true,如下所示://首页页面 class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin{ @override bool get wantKeepAlive => true;
-
可以了,实现效果如下所示: