浅析 Flutter TabController 监听调用两次

在开发过程中我们经常会用到 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() ,我们接下来重点看看这个方法。


图三
通过前面的分析我们知道了,duration != null && duration > Duration.zero ,那我们来看下 if 语句里面的代码,我们发现 notifyListeners() 调用了2次,在动画开始前后各调了一次。 那我们在看看 notifyListeners 方法。
图四

图五

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} ");
        }
      });
ok咯
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容