TabLayout踩坑记录-addOnTabSelectedListener()

接到一个需求,当recycleView的标题栏吸顶了,点击tablayout可以回到顶部,没啥大问题,不就是一个点击事件嘛。但是一波三折啊。

由于对Tablayout的使用不熟悉走了很多弯路,但是一些常规的使用和其他的控件没有什么区别嘛。addOnTabSelectedListener 用这个注册点击选中监听事件,在回调方法onTabSelected()里处理选中之后的操作。

由于当前tab是选中状态,再次点击时,并不会回调onTabSelected()方法,我当时脑子一热没有去想Google是不是考虑过这样的情况,最后的解决办法是自己手动给tabLayout注册一个点击事件,在点击事件里处理重复点击的逻辑。当时觉得自己很厉害。为了搞清楚为什么不会回调onTabSelected()方法,决定去看看源码。

现在回看tabLayout的源码发现自己还是太年轻了,哈哈哈哈哈。

addOnTabSelectedListener()里最后会调用这个addOnTabSelectedListener()方法。当然这不是我们关心的重点。

public void addOnTabSelectedListener(@Nullable BaseOnTabSelectedListener listener) {
  if (!selectedListeners.contains(listener)) {
    selectedListeners.add(listener);
  }
}

注意selectedListeners的调用地方,三个分发事件。看我们很熟悉的onTabSelected()就是在这里回调的,我们追下去。

private void dispatchTabSelected(@NonNull final Tab tab) {
  for (int i = selectedListeners.size() - 1; i >= 0; i--) {
    selectedListeners.get(i).onTabSelected(tab);
  }
}

private void dispatchTabUnselected(@NonNull final Tab tab) {
  for (int i = selectedListeners.size() - 1; i >= 0; i--) {
    selectedListeners.get(i).onTabUnselected(tab);
  }
}

private void dispatchTabReselected(@NonNull final Tab tab) {
  for (int i = selectedListeners.size() - 1; i >= 0; i--) {
    selectedListeners.get(i).onTabReselected(tab);
  }
}

看第一个if判断,就知道了问题所在,Google已经考虑到重复点击的情况了, dispatchTabReselected()处理重复点击,我们再回到三个分发事件里,onTabReselected()就是最后的处理了。我们在使用addOnTabSelectedListener()时,已经重写了onTabReselected()方法,真是远在天边,近在眼前啊,尤不自知。一下可以删除调好多代码,还是要多看看源码,说不定有已经封装好的API(哭泣)。

public void selectTab(@Nullable final Tab tab, boolean updateIndicator) {
  final Tab currentTab = selectedTab;

  if (currentTab == tab) {
    if (currentTab != null) {
      dispatchTabReselected(tab);
      animateToTab(tab.getPosition());
    }
  } else {
    final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
    if (updateIndicator) {
      if ((currentTab == null || currentTab.getPosition() == Tab.INVALID_POSITION)
          && newPosition != Tab.INVALID_POSITION) {
        // If we don't currently have a tab, just draw the indicator
        setScrollPosition(newPosition, 0f, true);
      } else {
        animateToTab(newPosition);
      }
      if (newPosition != Tab.INVALID_POSITION) {
        setSelectedTabView(newPosition);
      }
    }
    // Setting selectedTab before dispatching 'tab unselected' events, so that currentTab's state
    // will be interpreted as unselected
    selectedTab = tab;
    if (currentTab != null) {
      dispatchTabUnselected(currentTab);
    }
    if (tab != null) {
      dispatchTabSelected(tab);
    }
  }
}

当然大家还想知道selectTab()在哪里被调用的,我找出来了。在select()方法里,parent指的就是TabLayout了。

public void select() {
  if (parent == null) {
    throw new IllegalArgumentException("Tab not attached to a TabLayout");
  }
  parent.selectTab(this);
}

然后在添加tab里被调用,我们一般使用addTab()最后都会调用到这个方法来。

public void addTab(@NonNull Tab tab, int position, boolean setSelected) {
  if (tab.parent != this) {
    throw new IllegalArgumentException("Tab belongs to a different TabLayout.");
  }
  configureTab(tab, position); 
  addTabView(tab);

  if (setSelected) {
    tab.select();
  }
}

有什么疑问欢迎交流和讨论。

你可能感兴趣的:(踩坑记录,android,java)