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问题搜集的主要内容,如果未能解决你的问题,请参考以下文章

ViewPager问题搜集

ViewPager问题搜集

ViewPager问题搜集

如何实现具有不同片段/布局的 ViewPager

Android:将“ViewPager”动画从片段更改为片段

ViewPager 问题中的片段