使用MagicIndicator+ViewPager2出现requestLayout() improperly called by

一进入页面疯狂跑这个,页面样式顶部是banner

requestLayout() improperly called by com.yinp.proapp.view.viewpager2.
SimplePagerTitlePictureView{4a1e495 VFED..C..........0,0-540,99} 
during second layout pass: posting in next frame

经过测试发现:
1.没有图片的时候是不会发生的。
2.有图片的时候点击切换就会出现这个,解决办法setCurrentItem(index,true);
3.有图片的时候上面有CoordinatorLayout+banner,下面是ViewPager2+MagicIndicator,布局如下图,猜想问题出现原因是因为recyclerView中requestLayout造成的重新布局,测试停止banner自动,没有出现,猜想解决办法修改banner的源码中的RecyclerView增加一个setHasFixedSize(true)(没有试过)可能会解决。

本来没想过要去解决的,但是多次不同情况出现,就像从根本上解决一下。然后百度requestLayout() improperly called by,当然尝试了我看到的一系列做法,没有解决问题,就想着自己尝试下解决。

先找问题所在,提示了SimplePagerTitlePictureView(继承的TextView)这个类,刚好这个类就是表示图片+文字。关键代码如下,这是接口回调方法。

@Override
    public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
        if (leavePercent >= mChangePercent) {
            setTextColor(mNormalColor);
            if (mNormalDrawable != -1) {
                setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(context, mNormalDrawable), null, null);
            }
        } else {
            setTextColor(mSelectedColor);
            if (mSelectedDrawable != -1) {
                setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(context, mSelectedDrawable), null, null);
            }
        }
    }

    @Override
    public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
        if (enterPercent >= mChangePercent) {
            setTextColor(mSelectedColor);
            if (mSelectedDrawable != -1) {
                setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(context, mSelectedDrawable), null, null);
            }
        } else {
            setTextColor(mNormalColor);
            if (mNormalDrawable != -1) {
                setCompoundDrawablesWithIntrinsicBounds(null, ContextCompat.getDrawable(context, mNormalDrawable), null, null);
            }
        }
    }
打个断点,发现一直在回调这个两个方法,显而易见,需要溯源,看看在什么条件下调用这个两个方法,
过程略过。找到了CommonNavigator类:
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            if (this.mAdapter != null) {
                this.preparePositionData();
                if (this.mIndicator != null) {
                    this.mIndicator.onPositionDataProvide(this.mPositionDataList);
                }
                /**
                * 就是这儿
                */
                if (this.mReselectWhenLayout && this.mNavigatorHelper.getScrollState() == 0) {
                    this.onPageSelected(this.mNavigatorHelper.getCurrentIndex());
                    this.onPageScrolled(this.mNavigatorHelper.getCurrentIndex(), 0.0F, 0);
                    this.mNavigatorHelper.setmScrollState(-1);//这句是我在源码上添加的
                }
            }
        }
再打个断点在这儿,发现就是这里一直调用,那么问题原因已经找到了。分析一下为什么调用,作者的解释  
private boolean mReselectWhenLayout = true; // PositionData准备好时,是否重新选中当前页,为
true可保证在极端情况下指示器状态正确
        明显不用管,那么就是mNavigatorHelper.getScrollState()这个了,往前看:
public static void bind(final MagicIndicator magicIndicator, ViewPager2 viewPager) {
                    viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
                        @Override
                        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                            magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels);
                        }

                        @Override
                        public void onPageSelected(int position) {
                            magicIndicator.onPageSelected(position);
                        }

                        @Override
                        public void onPageScrollStateChanged(int state) {
                            magicIndicator.onPageScrollStateChanged(state);
                        }
                    });
                }
               表示指示器和viewpager2绑定页改动的状态回调, 其中onPageScrollStateChanged的state有0(什么都没做),1(滑动中),2(滑动停止)种状态,注意滑动时是1->2->0,继续往下看
                   public void onPageScrollStateChanged(int state) {
                       if (this.mNavigator != null) {
                           this.mNavigator.onPageScrollStateChanged(state);
                       }

                   }
                       public void onPageScrollStateChanged(int state) {
                           this.mScrollState = state;
                       }
    看到这个mScrollState值的赋值,而通过1->2->0来判断,最终mScrollState是等于0的,所以:
                         if (this.mReselectWhenLayout && this.mNavigatorHelper.getScrollState() == 0) {
                             this.onPageSelected(this.mNavigatorHelper.getCurrentIndex());
                             this.onPageScrolled(this.mNavigatorHelper.getCurrentIndex(), 0.0F, 0);
                         }
走在这一步的时候mReselectWhenLayout总是为true,mScrollState总是为0,
而onLayout又总是调用,自然也一直在走。要让他停止嘛很简单:
                    if (this.mReselectWhenLayout && this.mNavigatorHelper.getScrollState() == 0) {
                        this.onPageSelected(this.mNavigatorHelper.getCurrentIndex());
                        this.onPageScrolled(this.mNavigatorHelper.getCurrentIndex(), 0.0F, 0);
                        this.mNavigatorHelper.setmScrollState(-1);//这句是我在源码上添加的
                    }
这样除非走了ViewPager2的registerOnPageChangeCallback回调才会重新给mScrollState赋值,其他
时候就是-1,判断就不成立了,问题解决。当然我也去看了相关的demo,发现可以通过设置layout的形式
来实现图片文字布局,运行demo没有出现这个问题,只是遇到了想解决以下。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ActivityMainMenuBinding + BottomNavigationView + ViewPager2可以实现底部导航栏与ViewPager2的联动。下面是一个示例代码: ```java // 在Activity中使用DataBinding绑定布局 ActivityMainMenuBinding binding = ActivityMainMenuBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // 设置ViewPager2适配器 ViewPager2 viewPager = binding.viewPager; viewPager.setAdapter(new MyPagerAdapter(this)); // 设置BottomNavigationViewViewPager2的联动 BottomNavigationView bottomNavigationView = binding.bottomNavigationView; bottomNavigationView.setOnNavigationItemSelectedListener(item -> { switch (item.getItemId()) { case R.id.menu_home: viewPager.setCurrentItem(0); return true; case R.id.menu_dashboard: viewPager.setCurrentItem(1); return true; case R.id.menu_notifications: viewPager.setCurrentItem(2); return true; } return false; }); // 监听ViewPager2的页面切换事件,实现与BottomNavigationView的联动 viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { switch (position) { case 0: bottomNavigationView.setSelectedItemId(R.id.menu_home); break; case 1: bottomNavigationView.setSelectedItemId(R.id.menu_dashboard); break; case 2: bottomNavigationView.setSelectedItemId(R.id.menu_notifications); break; } } }); ``` 这段代码使用了DataBinding绑定了名为`ActivityMainMenuBinding`的布局文件。在布局文件中,包含了一个`ViewPager2`和一个`BottomNavigationView`。通过设置`ViewPager2`的适配器和监听器,以及`BottomNavigationView`的选中监听器和`ViewPager2`的页面切换监听器,实现了底部导航栏与ViewPager2的联动。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值