欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

ViewPager2+TabLayout监听Indicator指示器选中状态

程序员文章站 2022-06-16 10:04:36
项目中碰到一个问题,MainActivity中有一个FrameLayout,四个Fragment(主页、社区、商城、我的)切换。其中社区Fragment中有ViewPager2+TabLayout,下面还有4个子Fragment(推荐、关注、我的、好友)。对每个Fragment缓存rootView后,有个问题:切换到社区Fragment中,滑动ViewPager2到一半时,不松开手,切换到其他Fragment(比如切换到商城Fragment),再切换回社区Fragment,ViewPager2的滑动状态还保...

项目中碰到一个问题,MainActivity中有一个FrameLayout,四个Fragment(主页、社区、商城、我的)切换。其中社区Fragment中有ViewPager2+TabLayout,下面还有4个子Fragment(推荐、关注、我的、好友)。对每个Fragment缓存rootView后,有个问题:切换到社区Fragment中,滑动ViewPager2到一半时,不松开手,切换到其他Fragment(比如切换到商城Fragment),再切换回社区Fragment,ViewPager2的滑动状态还保持在上次的 滑动到一半的状态

ViewPager2+TabLayout监听Indicator指示器选中状态

正常状态是,松开手时,它会自动滑到指示器文本选中的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上面已经给了ViewPager2+TabLayout监听Indicator指示器选中状态

本文地址:https://blog.csdn.net/u014248939/article/details/108576826

相关标签: Android开发