Scroller原理


Scroller类,改变mScrollX和mScrollY值,实现视图内部平缓偏移。View的scrollTo和scrollBy方法也可以改变Scroll值,但它们一瞬间完成,体验不好。ViewPager和ScrollView的自动滚动效果都是通过它实现的。本文介绍它的实现原理。


在视图内部定义一个Scroller类,调用它的startScroll方法。

public void startScroll(int startX, int startY, int dx, int dy, int duration) {
    mMode = SCROLL_MODE;
    mFinished = false;
    mDuration = duration;
    mStartTime = AnimationUtils.currentAnimationTimeMillis();
    mStartX = startX;//X方向开始位置
    mStartY = startY;//Y方向开始位置
    mFinalX = startX + dx;//X方向结束的位置
    mFinalY = startY + dy;//Y方向结束的位置
    mDeltaX = dx;//X方法偏移的距离
    mDeltaY = dy;//Y方向偏移的距离
    mDurationReciprocal = 1.0f / (float) mDuration;
}

该方法有五个参数,默认duration是250毫秒,startX和startY是开始位置,dx和dy是偏移量,mStartTime初始化起始时间。根据起始位置和偏移计算结束位置。

dy正值,内部视图整体向上移动。
dy负值,内部视图整体向下移动。

从上面源码可以看出,该方法仅仅是初始化,在Scroller对象记录一些的值而已。调用后一定要invalidate方法视图刷新。
实现滚动的视图重写View的computeScroll方法。在invalidate方法刷新时,会回调到该方法中。

@Override
public void computeScroll() {
    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
        postInvalidate();//继续刷新UI。
    }
    super.computeScroll();
}

它在View类的源码中是空方法,视图渲染时触发,不重写无法实现滚动效果,Scroller的computeScrollOffset方法,计算Scroller当前偏移量。

public boolean computeScrollOffset() {
    if (mFinished) {//每次startScroll时,设置false。
        return false;
    }

    int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);

    if (timePassed < mDuration) {
        switch (mMode) {
            case SCROLL_MODE:
                final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
                mCurrX = mStartX + Math.round(x * mDeltaX);
                mCurrY = mStartY + Math.round(x * mDeltaY);
                break;
            case FLING_MODE:
             //Fling效果
        }
    }
    else {
        mCurrX = mFinalX;
        mCurrY = mFinalY;
        mFinished = true;
    }
    return true;
}

如果滚动已经结束,退出该方法,根据起始时间和当前时间,以及速率控制拦截器,计算此刻应该所在的位置mCurrX和mCurrY。scrollTo方法,滚动到该位置,postInvalidate方法继续刷新。刷新中继续回调computeScroll方法。因此,实现在一定时间内平滑滚动一定距离。
如果已经到达持续时间,将当前位置设置成结束位置,mFinished结束标志,下一次computeScrollOffset方法直接返回,computeScroll方法将不再滚动和刷新。
逻辑和补间动画实现原理类似。


总结

Scroller原理比较简单,重写View基类的computeScroll方法。
startScroll方法后,一定要刷新视图,否则不会出现滚动效果。


任重而道远

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android开发中View的滑动处理源码,该怎么看? Android 带你从源码的角度解析Scroller的滚动...
    ZHDelete阅读 12,067评论 1 15
  • Scroller Scroller是一个专门用于处理滚动效果的工具类,例如ViewPager,ListView等控...
    狮_子歌歌阅读 648评论 0 1
  • 1 代码示例 Scroller是用于View弹性滑动的工具类,可以平滑的移动view的位置,而不会产生突变的效果。...
    AndroidTony阅读 728评论 0 0
  • 在平时我们编程的时候,经常会用到倒计时这个功能,很多人不知道Android已经帮封装好了一个类,往往都自己写。现在...
    wtfysa阅读 721评论 0 2
  • 百度云刚推出时我就开始使用,虽然那时的传输速度、内容都不尽如人意,但是经过几年的改进,它在我的生活中也开始占据了一...
    江南雪阅读 499评论 0 0