在开发过程中我们经?;嵊玫?TabBar 、TabBarView ,当我们滑动TabBarView 组件时,TabController 的监听方法调用了1次;但当你点击 TabBar 的 Tab 时,TabController 的监听方法会调用了2次,很奇怪??,下面我们就来看看是什么原因以及解决办法。
问题
TabController 是继承至 ChangeNotifier,当我们调用 tabController.animateTo(index) 切换 tab 时,发现 addListener 监听方法调用了2次。
tabController = TabController(length: tabs.length, vsync: this)
..addListener(() {
print("监听切换tab ${tabController.index}");
});
tabController.animateTo(index); // 切换tab
原因
我们先来看下[图一] animateTo 方法,通过[图二] TabController 的初始化方法,我们知道 duration != null && duration > Duration.zero_animationDuration!=null&&duration > Duration.zero 。animateTo 方法里调用了 _changeIndex() ,我们接下来重点看看这个方法。
notifyListeners 方法里执行了 _listeners 集合里的方法,通过查看[图五] addListener 方法知道,_listeners 集合里面的方法 就是tabController 通过 addListener() 添加的 VoidCallback 监听方法。到此真相也就大白,图三的 notifyListeners() 调用了2次 ,也就是通过addListener() 添加的监听方法调了2次,所以我们会看到切换tab时 打印了2次日志。原因找到了,接下来我们看看解决办法。
解决
其实 _changeIndex 方法已经给了我们解诀办法,当第一次调用notifyListeners() 时,_indexIsChangingCount = 1;当第二次调用notifyListeners() 时,_indexIsChangingCount = 0,所有我们可以通过判断 _indexIsChangingCount 来决解问题,当然_indexIsChangingCount 是私有属性,我们不可以直接使用的,但是TabController 提供了 indexIsChanging 属性 {bool get indexIsChanging => _indexIsChangingCount != 0;} ,
问题解决:
tabController = TabController(length: tabs.length, vsync: this)
..addListener(() {
// or (tabController.indexIsChanging)
if (!tabController.indexIsChanging) {
print("监听切换tab ${tabController.index} ");
}
});