ViewPager问题搜集
Posted ShouCeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ViewPager问题搜集相关的知识,希望对你有一定的参考价值。
一、滑动距离设置
产品,不,测试任务当前滑动下一页时,需要距离太长。默认系统的距离:
try {
Field field = ViewPager.class.getDeclaredField("mTouchSlop"); //修改滑动距离
field.setAccessible(true);
field.setInt(this, touchSlop); //滑动长度大于150px的时候,ViewPager才进行滑动
} catch (Exception e) {
e.printStackTrace();
}
mTouchSlop是被系统认为系统滑动的最小距离,小于这个值系统不认为你在滑动,与设备有关。
二、RecyclerView嵌套ViewPager遇到的问题
1、RecyclerView上滑至使ViewPager到屏幕之外,再滑动下来,左右滑动ViewPager时没有动画。
ViewPager中有一个私有变量mFirstLayout,表示是否第一次显示布局,如果true,则使用无动画显示当前item,否则使用动画显示,源码:
public void setCurrentItem(int item, boolean smoothScroll) {
mPopulatePending = false;
setCurrentItemInternal(item, smoothScroll, false);
}
public int getCurrentItem() {
return mCurItem;
}
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
setCurrentItemInternal(item, smoothScroll, always, 0);
}
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;
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会走onAtatchedToWindow,而问题就出在onAttachToWindow.:
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mFirstLayout = true;
}
在onAttachedToWindow方法中,mFirstLayout被重置为true,所以下一次滚动就没有动画。
通过反射把mFirstLayout重置为false,由于是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左右页面滑动一半卡主了
当ViewPager不可见之后,在另一个页面操作了数据,需要ViewPager切换tab的时候,出现两个tab页个出现一半的情况,这个问题的主要原因是,当ViewPager正在执行动画的时候,如果调用了detachWindow,则会导致动画终止,可能会出现两个tab页同时存在的情况。具体到项目中的场景:第一种case:当回到viewpager页面的时候,onResume时又重新拉取数据源,notify的时候会激活detach的调用。另外一种case:如果正在执行tab切换的行为,滑动了RecyclerView,由于存在复用的情况,不可见的ViewPager会执行detach方法。这两case都有可能可能会导致detachWindow,这样便会终止动画的执行。分析代码如下:
@Override
protected void onDetachedFromWindow() {
removeCallbacks(mEndScrollRunnable);
// To be on the safe side, abort the scroller
if ((mScroller != null) && !mScroller.isFinished()) {
mScroller.abortAnimation();
}
super.onDetachedFromWindow();
}
可以再detachwindow的时候,判断Activity是否已经销毁,如果没有销毁,则继续执行动画。
@Override
protected void onDetachedFromWindow() {
if (hasActivityDestroy) {
super.onDetachedFromWindow();
}
}
public void setHasDestroy(boolean hasDestroy) {
hasActivityDestroy= hasDestroy;
}
以上官方在android8.0不支持反射,可以考虑使用RecyclerView+SnapHelper实现。
参考:
1、https://blog.csdn.net/u011002668/article/details/72884893
以上是关于ViewPager问题搜集的主要内容,如果未能解决你的问题,请参考以下文章