Scroller源碼分析

一、構造器java

    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首乾的主要工做時初始化變量:ui

 mFinished :  判斷滾動是否中止,初始化爲truethis

 mInterpolator: 插值器,計算滾動距離、速度的公式、方式,可自定義。spa

mPpi:像素密度,每英寸所擁有的像素數目,density是像素密度,以160f爲基數,能夠是160/240/320等。code

mDeceleration: 加速度,暫時不知幹啥用的。ViewConfiguration保存了超時、尺寸、距離等一些標準常數。保存的一些常數很是有用,好比手指觸摸屏幕時的點擊和滑動的最低距離。orm

mFlywheel:暫不知,
ip

mPhysicalCoeff:一個係數。
ci

新建Scroller實例後,最經常使用的方法之一是 startScroll():get

    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來增長的,而是以使用的時間+擴展的時間

相關文章
相關標籤/搜索