码迷,mamicode.com
首页 > 其他好文 > 详细

ViewPager的onPageScrolled回调不完整

时间:2016-05-07 07:13:17      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:

问题描述
在开发时我们可能经常需要使用到ViewPager的onPageScrolled(int position, float offset, int offsetPixels)方法来获取ViewPager的滚动信息,然而在使用中发现onPageScrolled并不能准确地回调每一个滚动信息,可能会错过一些信息,在一些手机上甚至连onPageScrolled滚动停止(offset参数为0的状态)的信息也不会回调。
问题分析
通过阅读ViewPager的源码知道,ViewPager的滚动是配合Scroller实现的,而Scroller的实现原理就是在Scroller的动画时间内不断的调整View的位置然后重绘布局,而onPageScrolled的回调和view位置的调整是同步的,但是View的重新绘制是耗时的,这也就是说,onPageScrolled的回调频率和view的重新绘制相关联,如果手机的性能差一点,View的刷新次数少,那么onPageScrolled的回调次数也会相对减少。
后来又发现onPageScrolled的最终状态的回调在部分手机上存在问题,有部手机很卡也能正常回调,有部手机比较流畅却也没有回调,所以可能和安卓系统版本有关,于是对比了一下ViewPager在各个版本的实现,发现了问题;我们知道要通过Scroller实现滚动需要实现computeScroll方法,在这个方法里判断滚动是否已完成,没有完成则通过scrollTo方法滚动到相应的位置。下面是ViewPager的实现:

@Override
public void computeScroll() {
    if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
        int oldX = getScrollX();
        int oldY = getScrollY();
        int x = mScroller.getCurrX();
        int y = mScroller.getCurrY();
        if (oldX != x || oldY != y) {
            scrollTo(x, y);
            if (!pageScrolled(x)) {
                mScroller.abortAnimation();
                scrollTo(0, y);
            }
        }

        // Keep on drawing until the animation has finished.
        ViewCompat.postInvalidateOnAnimation(this);
        return;
    }

    // Done with scroll, clean up state.
    completeScroll(true);
}

可以看到如果mScroller没有Finished则会通过pageScrolled回调onPageScrolled 并滚动到指定位置,如果已经Finished则调用completeScroll方法完成最终的状态,我们的问题是onPageScrolled在最终状态的调用在有些手机上不正常,所以这其中的玄机很可能发生在completeScroll方法中,于是进一步查看completeScroll方法:

private void completeScroll(boolean postEvents) {
    boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;
    if (needPopulate) {
        // Done with scroll, no longer want to cache view drawing.
        setScrollingCacheEnabled(false);
        mScroller.abortAnimation();
        int oldX = getScrollX();
        int oldY = getScrollY();
        int x = mScroller.getCurrX();
        int y = mScroller.getCurrY();
        if (oldX != x || oldY != y) {
            scrollTo(x, y);
            if (x != oldX) {
                pageScrolled(x);
            }
        }
    }
    .....省略部分代码
}

这里主要注意下面这个判断,通过查阅各个版本的源码,发现只有在api23以上才有这个判断

if (x != oldX) {
      pageScrolled(x);
}

而这个判断就是回调onPageScrolled方法的。所以答案就出来了:假如不是api23的手机,如果scroller已经finish状态(动画的时间到),而view还没来得及完全刷新,就会走到completeScroll方法,而这时api23以下的手机不回回调onPageScrolled方法。

问题总结
ViewPager的onPageScrolled方法比较不可靠,如果有一些比较关键的代码要放在这里处理最好改用其它方式实现,不然稳定性不高,容易出问题。

ViewPager的onPageScrolled回调不完整

标签:

原文地址:http://blog.csdn.net/dct8888/article/details/51331693

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!