android Scroller浅析

Scroller主要用在View的弹性滑动上。

Scroller用法主要分为下面三步:

1. 

Scroller scroller = new Scroller(mContext);

2.

/**
 * @param startX        起始坐标x
 * @param startY        起始坐标y
 * @param dx            x坐标的变化量,如果dx>0,那么View的内容向左滑动
 * @param dy            y坐标的变化量,如果dy>0,那么View的内容向上滑动
 * @param duration      滑动时间(ms)
 */
private void smoothScroll(int startX, int startY, int dx, int dy, int duration)
{
    mScroller.startScroll(startX, startY, dx, dy, duration);
    invalidate();
}

3.

@Override
public void computeScroll()
{
    if(mScroller.computeScrollOffset())
    {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
        postInvalidate();
    }
}

概括来说,三步分别为:1. 初始化Scroller;2. 在UI主线程中,调用startScroll和invalidate();3. 重写View类中的public void computeScroll()方法。通过mScroller.computeScrollOffset()计算出最新的滑动位置,根据其返回值得知,滑动是否结束。若滑动未结束,则调用scrollTo到计算出来的滑动位置,并且调用postInvalidate()方法。

主要原理分析的话,需要分析一下Scroller源码中的startScroll()方法和computeScrollOffset()方法。

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;
    mStartY = startY;
    mFinalX = startX + dx;
    mFinalY = startY + dy;
    mDeltaX = dx;
    mDeltaY = dy;
    mDurationReciprocal = 1.0f / (float) mDuration;
}

startScroll()方法主要是初始化一些参数。具体每个参数含义,已经在之前分析过,故不再累述。

/**
 * Call this when you want to know the new location.  If it returns true,
 * the animation is not yet finished.
 */ 
public boolean computeScrollOffset() {
    if (mFinished) {
        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:
            final float t = (float) timePassed / mDuration;
            final int index = (int) (NB_SAMPLES * t);
            float distanceCoef = 1.f;
            float velocityCoef = 0.f;
            if (index < NB_SAMPLES) {
                final float t_inf = (float) index / NB_SAMPLES;
                final float t_sup = (float) (index + 1) / NB_SAMPLES;
                final float d_inf = SPLINE_POSITION[index];
                final float d_sup = SPLINE_POSITION[index + 1];
                velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
                distanceCoef = d_inf + (t - t_inf) * velocityCoef;
            }

            mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
                
            mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
            // Pin to mMinX <= mCurrX <= mMaxX
            mCurrX = Math.min(mCurrX, mMaxX);
            mCurrX = Math.max(mCurrX, mMinX);
                
            mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
            // Pin to mMinY <= mCurrY <= mMaxY
            mCurrY = Math.min(mCurrY, mMaxY);
            mCurrY = Math.max(mCurrY, mMinY);

            if (mCurrX == mFinalX && mCurrY == mFinalY) {
                mFinished = true;
            }

            break;
        }
    }
    else {
        mCurrX = mFinalX;
        mCurrY = mFinalY;
        mFinished = true;
    }
    return true;
}

computeScrollOffset主要工作就是计算当前时间点View内容的x坐标和y坐标。其中,mInterpolator默认使用的是ViscousFluidInterpolator。ViscousFluidInterpolator implements  Interpolator ,是Scroller.java中的一个静态类。Viscous的意思是粘性的,Fluid的意思是液体的。ViscousFluidInterpolator就是指一种类似粘性液体的Interpolator。

最后,还想再分析一下,整个View滑动的流程:a. startScroll()给mScroller传递了滑动的相关参数,调用invalidate()会触发的重绘。b. 在View重绘的时候,View的computeScroll()方法会被调用。通过调用mScroller.computeScrollOffset()计算当前View内容的位置,并通过返回值得知,滑动是否结束。若滑动未结束,调用scrollTo()方法使View的内容滑动到刚才计算出的位置,并调用postInvalidate()继续触发重绘流程。c. 步骤b不断被重复,直到mScroller.computeScrollOffset()返回true,即滑动结束为止。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值