接到一个需求,当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();
}
}
有什么疑问欢迎交流和讨论。