方式一:
使用Flutter自带的Widget(TabBar + TabBarView)实现,如下
List _tabs = ["A", "B", "C"];
@override
void initState() {
super.initState();
_tabController = TabController(length: _tabs.length, vsync: this);
_tabController.addListener(() {
bool indexIsChanging = _tabController.indexIsChanging;
if (!indexIsChanging) {
logx("index : " + _tabController.index.toString());
}
});
}
// build方法里面返回
return Column(
children: [
Container(
child: TabBar(
tabs: _tabs
.map((e) => Tab(
text: e,
))
.toList(),
controller: _tabController,
unselectedLabelColor: XColor.colorBlackStyle,
labelColor: XColor.colorStyle,
indicatorSize: TabBarIndicatorSize.label,
),
),
Expanded(
child: TabBarView(
children: _tabs.map((e) => Container(child: Text(e + "的内容"),)).toList(),
controller: _tabController,
),
)
],
)
最开始我是不想用这种方法的,所以才有了下面第二种方法,我不想用这种方式的一个原因是一开始我没找到TabBar或者TabBarView中类似于PageView中onPageChanged的监听,不知道当前页面的index是多少,我要做到切换到第二个或者后面的时候,第一个页面中的轮播图定时器取消,让它不再自动滚动。
既然TabBar或者TabBarView中没有参数去监听,我就注意到了TabController,然后我就看了一下它里面的方法,有一个addListener方法,顾名思义,就是添加一个监听。具体监听什么呢?打印一下日志
print("listener");
结果每次滑动的时候都会调用一下,再去看TabController里面的方法或者变量,里面有
index 和 indexIsChanging
前一个应该就是我所需要的index了,后面的字面意思就是index是否改变中(这个暂且不谈是干嘛的),然后打印一下index,
print(_tabController.index);
结果滑动页面的时候就打印当前页面对应的index了。这里有一个小问题,就是手指滑动页面的时候到打印出index有明显间隔。
后来我再点击上面的TabBar来切换页面,这时候index日志会打印两次,第一次打印是在点击的时候打印的,第二次就和上面有延时的打印时间差不多间隔。因为才学Flutter几天,具体原理不太清除,这时候我想起还有
indexIsChanging 这个变量,一起和index打印一下,
结果indexIsChanging自然也是打印了两遍,第一次为true,第二次为false。从结果来看,第一次为true时,是因为点击Tab,index正好处于切换状态中,至于第二次为false,是因为页面已经切换完成(具体原因感兴趣的同学可以去看源码)。
所以由indexIsChanging可以来排除第一次返回的index,具体代码如下
_tabController.addListener(() {
bool indexIsChanging = _tabController.indexIsChanging;
if (!indexIsChanging) {
print(_tabController.index);
}
});
这样就可以实现滑动页面+Tab的效果了,缺点只有在监听页面切换的时候,获取index的时间要稍微延时一会,总体来说问题不大。
*******************************************************************************************************************************************************************************************
方式二:
在我之前没有办法获取tab页面切换监听的时候我用到了第二种方式,当时的想法是既然TabBarView没有onPageChanged监听,我可以使用PageView的啊。然后上网查找,找到一位开发者的替换方式,先贴代码。
开始就自定义了新的TabBarView,如下:
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class FixTabBarView extends StatefulWidget {
const FixTabBarView({
Key key,
@required this.children,
@required this.tabController,
@required this.pageController,
this.physics,
this.dragStartBehavior = DragStartBehavior.start,
this.onTabIndexChanged,
}) : assert(children != null),
assert(dragStartBehavior != null),
super(key: key);
final TabController tabController;
final PageController pageController;
final List<Widget> children;
final ScrollPhysics physics;
final DragStartBehavior dragStartBehavior;
final ValueChanged<int> onTabIndexChanged;
@override
_FixTabBarViewState createState() => _FixTabBarViewState();
}
class _FixTabBarViewState extends State<FixTabBarView> {
@override
void dispose() {
super.dispose();
widget.tabController.dispose();
widget.pageController.dispose();
}
@override
Widget build(BuildContext context) {
return PageView(
dragStartBehavior: widget.dragStartBehavior,
physics: widget.physics,
controller: widget.pageController,
children: widget.children,
onPageChanged: (index) {
widget.onTabIndexChanged(index);
widget.tabController.animateTo(index);
},
);
}
}
最开始是没有onTabIndexChanged这个监听的,是因为我个人需要后面自己加的。你们也可以根据自己需求来修改
使用方法如下:
List _tabs = ["A", "B", "C"];
@override
void initState() {
super.initState();
_tabController = TabController(length: _tabs.length, vsync: this);
_pageController = PageController();
}
return Column(
children: [
Container(
child: TabBar(
tabs: _tabs
.map((e) => Tab(
text: e,
))
.toList(),
controller: _tabController,
unselectedLabelColor: XColor.colorBlackStyle,
labelColor: XColor.colorStyle,
indicatorSize: TabBarIndicatorSize.label,
onTap: (index) {
_pageController.jumpToPage(index);
},
),
),
Expanded(
child: FixTabBarView(
tabController: _tabController,
pageController: _pageController,
children: _tabs.map((e) => Container(child: Text(e + "的内容"),)).toList(),
onTabIndexChanged: (index){
logx("onTabIndexChanged: " + index.toString());
},
),
)
],
)
先说一下优点:
1:在我没发现第一种方法里面获取监听的方式之前,我觉得全是优点,QAQ
现在再说一下缺点:
1:构造相对复杂,页面切换的监听在FixTabBarView里面的onTabIndexChanged中,相对方式一,这里还要再加一个PageController来进行绑定,并且在点击顶部tab的时候还要在TabBar的onTab事件里面手动添加
_pageController.jumpToPage(index);
切换页面的方法。
2:手动在FixTabBarView滑动的时候,如果页面没有切换完成,顶部的指示器是不会移动做出改变的,只有在页面切换完成,tab的指示器才会在最后的时候滑动到相应的index,这样显得有点突兀。
3:点击顶部tab去切换的时候,底部的页面没有左右滑动的切换效果,会有点突兀。
对比看来,还是第一种方法更好用,而第二种方法也是在学习过程中的成果,在此记录一下,希望可以帮助需要的朋友。