关于RecyclerView嵌套ViewPager的卡钝和动画失效问题


问题

在RecyclerView中使用ViewPager时, 会出现两个常见的bug:

问题

Bug

1

RecyclerView滚动上去, 直至ViewPager看不见, 再滚动下来, ViewPager下一次切换没有动画

2

ViewPager滚动到一半的时候, RecyclerView滚动上去, 再滚动下来, ViewPager会卡在一半

原因

  • ViewPager里有一个私有变量mFirstLayout, 它是表示是不是第一次显示布局, 如果是true, 则使用无动画的方式显示当前item, 如果是false, 则使用动画方式显示当前item
  • 当ViewPager滚动上去后, 因为RecyclerView的回收机制, ViewPager会走onDetachFromWindow, 当再次滚动下来时, ViewPager会走onAttachedToWindow, 而问题就出在onAttachToWindow.

解决方案

​重写onAttachedToWindow​​​ fix ​​ViewPager滚动到一半的时候, RecyclerView滚动上去, 再滚动下来, ViewPager会卡在一半​

  • Java
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (isLayout && getAdapter() != null && getAdapter().getCount() > 0) {//isLayout是记录是否已经布局到界面的全局变量
try {
//fix 使用RecyclerView + ViewPager bug
Field mScroller = ViewPager.class.getDeclaredField("mFirstLayout");
mScroller.setAccessible(true);
mScroller.set(this, false);
} catch (Exception e) {
e.printStackTrace();
}
}
start();
}
  • Kotlin
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (_isLayout && adapter != null && adapter!!.count > 0) {
try {
//fix 使用RecyclerView + ViewPager bug
val mScroller = ViewPager::class.java.getDeclaredField("mFirstLayout")
mScroller.isAccessible = true
mScroller[this] = false
} catch (e: Exception) {
e.printStackTrace()
}
}
start()
}

​重写onDetachedFromWindow​​​ fix ​​RecyclerView滚动上去, 直至ViewPager看不见, 再滚动下来, ViewPager下一次切换没有动画​

  • Java
@Override
protected void onDetachedFromWindow() {
//fix 使用RecyclerView + ViewPager bug
if (((Activity) getContext()).isFinishing()) {
super.onDetachedFromWindow();
}
}
  • Kotlin
override fun onDetachedFromWindow() {
//fix 使用RecyclerView + ViewPager bug
if ((context as Activity).isFinishing) {
super.onDetachedFromWindow()
}
}