一进入页面疯狂跑这个,页面样式顶部是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没有出现这个问题,只是遇到了想解决以下。