RecyclerView中使用ViewPager问题
问题
在RecyclerView中使用ViewPager时,会出现两个常见的bug:
- RecyclerView滚动上去,直至ViewPager看不见,再滚动下来,ViewPager下一次切换没有动画
- 当ViewPage滚动到一半的时候,RecyclerView滚动上去,再滚动下来,ViewPager会卡在一半
问题1:原因
ViewPager里有一个私有变量mFirstLayout,它是表示是不是第一次显示布局,如果是true,则使用无动画的方式显示当前item,如果是false,则使用动画方式显示当前item。
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
...
if (mFirstLayout) {
// We don't have any idea how big we are yet and shouldn't have any pages either.
// Just set things up and let the pending layout handle things.
mCurItem = item;
if (dispatchSelected) {
dispatchOnPageSelected(item);
}
requestLayout();
} else {
populate(item);
scrollToItem(item, smoothScroll, velocity, dispatchSelected);
...
}
当ViewPager滚动上去后,因为RecyclerView的回收机制,ViewPager会走onDetachFromWindow,当再次滚动下来时,ViewPager会走onAttachedToWindow,而问题就出在onAttachToWindow。
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mFirstLayout = true;
}
原来如此,在onAttachedToWindow中,mFirstLayout被重置为true,所以下一次滚动就没有动画。
问题1:解决方法
重写onAttachedToWindow方法,把mFirstLayout再重置成false,因为mFirstLayout是private变量,我们不能直接访问,所以只能反射了。
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
try {
Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
mFirstLayout.setAccessible(true);
mFirstLayout.set(this, false);
getAdapter().notifyDataSetChanged();
setCurrentItem(getCurrentItem());
} catch (Exception e) {
e.printStackTrace();
}
}
问题2:原因
直接来看ViewPager的onDetachFromWindow方法
@Override
protected void onDetachedFromWindow() {
removeCallbacks(mEndScrollRunnable);
// To be on the safe side, abort the scroller
if ((mScroller != null) && !mScroller.isFinished()) {
mScroller.abortAnimation();
}
super.onDetachedFromWindow();
}
尼玛,直接把动画强行停掉了。
问题2:解决方法
想来想去,没什么好办法,只能想办法保护了
@Override
protected void onDetachedFromWindow() {
if (hasActivityDestroy) {
super.onDetachedFromWindow();
}
}
public void setHasDestroy(boolean hasDestroy) {
hasActivityDestroy= hasDestroy;
}
当activitydestroy的时候,给自定义ViewPager一个标志位hasActivityDestroy,只有hasActivityDestroy为true的时候,才调用父类的super.onDetachedFromWindow();