Scroller源码分析

1、构造器

    public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
        mFinished = true;
        mInterpolator = interpolator;
        mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
        mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
        mFlywheel = flywheel;

        mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
    }

  Scroller有三个构造器,这是最终被调用的,其余两个是

  public Scroller(Context context) {
        this(context, null);
    }
    
    public Scroller(Context context, Interpolator interpolator) {
        this(context, interpolator,
                context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
    }

从构造器中,我们可以看到Scroller首干的主要工作时初始化变量:

 mFinished :  判断滚动是否停止,初始化为true

 mInterpolator: 插值器,计算滚动距离、速度的公式、方式,可自定义。

mPpi:像素密度,每英寸所拥有的像素数目,density是像素密度,以160f为基数,可以是160/240/320等。

mDeceleration: 加速度,暂时不知干啥用的。ViewConfiguration保存了超时、尺寸、距离等一些标准常数。保存的一些常数非常有用,比如手指触摸屏幕时的点击和滑动的最低距离。

mFlywheel:暂不知,

mPhysicalCoeff:一个系数。

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

    这个方法初始化一下变量:

    mMode : SCROLL_MODE  另一个为FLING_MODE。

    mFinished : false,

    mStartTime : AnimationUtils.currentAnimationTimeMillis()

    mStartX : x开始位置

    mStartY : y开始位置

    mFinalX:x结束位置,是x开始位置加上x移动距离  mStartX+dx

    mFinalY:y结束位置,是y开始位置加上y移动距离,mStartY+dy

    mDeltaX:x移动距离

    mDeltaY:y移动距离

    mDurationReciprocal :时间倒数,1/mDuration。

   另一个经常用到的方法是 :

 public boolean computeScrollOffset() {
        if (mFinished) {
            return false;
        }

        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
    
        if (timePassed < mDuration) {
            switch (mMode) {
            case SCROLL_MODE:
                float x = timePassed * mDurationReciprocal;
    
                if (mInterpolator == null)
                    x = viscousFluid(x); 
                else
                    x = mInterpolator.getInterpolation(x);
    
                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;
    }

   当想知道最新的控件位置时,可以调用这个方法,如果返回true说明动画还没结束。

   方法入口会判断isFinished 为true说明动画已经结束,返回false。

   if (timePassed < mDuration) {}  判断动画时间是否超时,

   根据mMode计算不同的滚动模式下的位置,

    SCROLL_MODE :  

  float x = timePassed * mDurationReciprocal;

     使用的时间*时间的倒数,得到用时时间百分比。

if (mInterpolator == null)
  x = viscousFluid(x);

   没有设置插值器时,使用默认插值器,设置插值器的话就使用自定义的插值器

  static float viscousFluid(float x)
    {
        x *= sViscousFluidScale;
        if (x < 1.0f) {
            x -= (1.0f - (float)Math.exp(-x));
        } else {
            float start = 0.36787944117f;   // 1/e == exp(-1)
            x = 1.0f - (float)Math.exp(1.0f - x);
            x = start + x * (1.0f - start);
        }
        x *= sViscousFluidNormalize;
        return x;
    }

   代码看不太懂,应该是幂指数相关的。

 mCurrX = mStartX + Math.round(x * mDeltaX);
 mCurrY = mStartY + Math.round(x * mDeltaY);

   计算当前x、y坐标,此时x的类似于距离百分比

   SCROLL_FLING 模式:

    根据固有公式计算速度’和当前x‘y坐标。

    其中如下取值的方法可以借鉴。

 mCurrX = Math.min(mCurrX, mMaxX);
 mCurrX = Math.max(mCurrX, mMinX);


 public final void setFriction(float friction) {
        mDeceleration = computeDeceleration(friction);
        mFlingFriction = friction;
    }

  设置滑动时的摩擦力数量。

public final boolean isFinished() {
        return mFinished;
    }

 返回滚动状态是否结束

    public final void forceFinished(boolean finished) {
        mFinished = finished;
    }

修改isFinished的值

public final int getDuration() {
        return mDuration;
    }

返回滚动消耗的时间

    public final int getCurrX() {
        return mCurrX;
    }

返回当前滚动中x的位置

    public final int getCurrY() {
        return mCurrY;
    }

返回当前滚动中y的位置

    public float getCurrVelocity() {
        return mMode == FLING_MODE ?
                mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f;
    }

获取当前速率。当前是Fling模式是

public final int getStartX() {
        return mStartX;
    }
    
   
    public final int getStartY() {
        return mStartY;
    }
    
  
    public final int getFinalX() {
        return mFinalX;
    }
    
    
    public final int getFinalY() {
        return mFinalY;
    }

这四个方法分别是返回开始x’y坐标,返回结束x、y坐标

 public void abortAnimation() {
        mCurrX = mFinalX;
        mCurrY = mFinalY;
        mFinished = true;
    }

    终止动画,将当前x,y坐标更新为最终的x、y坐标,并将mFinished置为true标明动画结束

  public void extendDuration(int extend) {
        int passed = timePassed();
        mDuration = passed + extend;
        mDurationReciprocal = 1.0f / mDuration;
        mFinished = false;
    }

   这个方法要注意扩展的时间不是以原来的duration来增加的,而是以使用的时间+扩展的时间




你可能感兴趣的:(android,scroller)