项目中碰到一个问题,MainActivity中有一个FrameLayout,四个Fragment(主页、社区、商城、我的)切换。其中社区Fragment中有ViewPager2+TabLayout,下面还有4个子Fragment(推荐、关注、我的、好友)。对每个Fragment缓存rootView后,有个问题:切换到社区Fragment中,滑动ViewPager2到一半时,不松开手,切换到其他Fragment(比如切换到商城Fragment),再切换回社区Fragment,ViewPager2的滑动状态还保持在上次的 滑动到一半的状态
正常状态是,松开手时,它会自动滑到指示器文本选中的positon对应的Fragment
但现在切换到其他Fragment再切换回来后,它没有自动滑动到Tab指示器文本选中position对应的的Fragment
想了个办法,监听TabLayout的指示器中的文本的选中状态,然后在切换到其他Fragment时(主页、商城、我的),手动设置到对应的Fragment(推荐、关注、我的、好友)。这样就不会出现ViewPager2卡在中间的情况了
试了两个监听器:
new ViewPager2.OnPageChangeCallback() { //只有松开手,选中后,才会调用 @Override public void onPageSelected(int position) { super.onPageSelected(position); } //当ViewPager2左右滑动超过一定距离后position的位置会更新,但是Tab指示器的文本选中position和这个不能准确对应,因此放弃。Tab指示器的文本选中position ViewPager2滑动超过一半的样子 就会更新,但这里的position,要大概超过四分之三才会更新 @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { super.onPageScrolled(position, positionOffset, positionOffsetPixels); mPosition = position; logD("mPosition=" + mPosition); } //滑动状态,比如拖拽、松手等等 @Override public void onPageScrollStateChanged(int state) { super.onPageScrollStateChanged(state); } };
这个也不行,也是松开手后才会回调。我要的是没有松手也能监听到Tab指示器文本选中状态
new TabLayout.OnTabSelectedListener() { //选中 @Override public void onTabSelected(TabLayout.Tab tab) { mPosition = tab.getPosition(); logD("mPosition=" + mPosition); } //取消选中 @Override public void onTabUnselected(TabLayout.Tab tab) { } //重复选中 @Override public void onTabReselected(TabLayout.Tab tab) { } };
显然系统没有提供监听器来满足我的需求,那就只能想办法了
在源码里找,滑动时Tab指示器文本会切换选中状态,找到它是何时、在哪被切换的,那就是我要的监听了
从vp_community.setCurrentItem(mPosition);的源码里找,setCurrentItem调用后指示器文本选中会改变,找到修改指示器文本选中状态的代码,然后再找这代码被哪里调用,调用的地方的判断条件就是我要的了
辗转找到了TabLayoutMediator,滑动ViewPager2的时候Tab会改变,那应该是这个类里做了什么操作(ViewPager2和TabLayout的联动是由这个类管理的)
找到这个方法,滑动ViewPager2时会被回调
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
TabLayout tabLayout = tabLayoutRef.get();
if (tabLayout != null) {
// Only update the text selection if we're not settling, or we are settling after
// being dragged
boolean updateText =
scrollState != SCROLL_STATE_SETTLING || previousScrollState == SCROLL_STATE_DRAGGING;
// Update the indicator if we're not settling after being idle. This is caused
// from a setCurrentItem() call and will be handled by an animation from
// onPageSelected() instead.
boolean updateIndicator =
!(scrollState == SCROLL_STATE_SETTLING && previousScrollState == SCROLL_STATE_IDLE);
tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);//TabLayout指示器文本选中状态就是在这里被更改的
}
}
但好像并没有条件判断的代码。调试了下,看滑动(不松手)导致TabLayout指示器文本选中状态改变时,这几个值会不会有什么不同,如果有,我就把这段代码拿过去用就行了。不过调试发现并没有改变
然后继续往下找
public void setScrollPosition(
int position,
float positionOffset,
boolean updateSelectedText,
boolean updateIndicatorPosition) {
final int roundedPosition = Math.round(position + positionOffset);
if (roundedPosition < 0 || roundedPosition >= slidingTabIndicator.getChildCount()) {
return;
}
// Set the indicator position, if enabled
if (updateIndicatorPosition) {
slidingTabIndicator.setIndicatorPositionFromTabPosition(position, positionOffset);
}
// Now update the scroll position, canceling any running animation
if (scrollAnimator != null && scrollAnimator.isRunning()) {
scrollAnimator.cancel();
}
scrollTo(calculateScrollXForTab(position, positionOffset), 0);
// Update the 'selected state' view as we scroll, if enabled
if (updateSelectedText) {
setSelectedTabView(roundedPosition);//这里,继续往下找
}
}
但是始终没有条件判断,没有什么时候切换的条件判断
private void setSelectedTabView(int position) {
final int tabCount = slidingTabIndicator.getChildCount();
if (position < tabCount) {
for (int i = 0; i < tabCount; i++) {
final View child = slidingTabIndicator.getChildAt(i);
child.setSelected(i == position);//但是找到了这个,继续往下,就到View的源码里了。原来Tab的文本选中状态是通过View的setSelected方法来设置的
child.setActivated(i == position);
}
}
}
然后试了下,可以获取到TabLayout指示器文本选中的position。这个能获取到滑动时未松手状态 选中的Tab的position
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
for (int i = 0; i < tl_title.getTabCount(); i++) {
TabLayout.Tab tab = tl_title.getTabAt(i);
if (tab.view.isSelected()) {
logD("tab.getPosition()=" + tab.getPosition());
mPosition = tab.getPosition();
break;
}
}
}
博客写到一半的时候发现position上面已经给了