大家都知道,
RecyclerView
没有addHeaderView
的方法,所以,要实现添加头部
,就需要在RecyclerAdapter
中进行。将
ViewPager
作为RecyclerView
的其中一项
过程中发现两个问题:1.当
ViewPager
不可见时,会执行其onDetachedFromWindow
方法,再次可见时会执行onAttachedToWindow
方法。
- 在Android4.0上会出现第一次自动滑动没有动画效果。
- 在Android5.0上会出现第一次滑动不仅没有动画效果,而且连View都没有。
2.当ViewPager自动滑动到一半的时候,将其隐藏后,无法自动滑完。会出现滑一半的情况。
第一个问题
原因
根据源码可以看出是mFirstLayout的问题
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//这是自动将mFirstLayout设置为了true
mFirstLayout = true;
}
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
if (mAdapter == null || mAdapter.getCount() <= 0) {
setScrollingCacheEnabled(false);
return;
}
if (!always && mCurItem == item && mItems.size() != 0) {
setScrollingCacheEnabled(false);
return;
}
if (item < 0) {
item = 0;
} else if (item >= mAdapter.getCount()) {
item = mAdapter.getCount() - 1;
}
final int pageLimit = mOffscreenPageLimit;
if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {
// We are doing a jump by more than one page. To avoid
// glitches, we want to keep all current pages in the view
// until the scroll ends.
for (int i=0; i<mItems.size(); i++) {
mItems.get(i).scrolling = true;
}
}
final boolean dispatchSelected = mCurItem != item;
//这里根据mFirstLayout判断选择ViewPager在切换页面时的效果
//由此可以看出,当ViewPager隐藏后再次显示时,走的是第一步,没有动画效果
//并且会导致5.0以上的系统出现更多的bug
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,在onAttachedToWindow中将mFirstLayout设置为false,但是mFirstLayout是私有变量,所以必须用到反射
如
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
/**
* 坑,解决在RecyclerView中使用的bug
* 设ViewPager中有3张照片
* 当ViewPager滑动一遍之后,向下滑动RecyclerView列表
* 直到完全隐藏此ViewPager,并执行了onDetachedFromWindow
* 再回来时,将会出现bug,第一次滑动时没有动画效果,并且,经常出现view没有加载的情况
*/
try {
Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
mFirstLayout.setAccessible(true);
mFirstLayout.set(this, false);
adapter.notifyDataSetChanged();
setCurrentItem(getCurrentItem());
} catch (Exception e) {
e.printStackTrace();
}
}