android scroller的原理分析

谷歌爲何要設計一個scroller?android

Android中全部的的View都有一個實際界面大於可視界面的,這就涉及到界面的移動或者說偏移,View這個類提供了scrollTo和ScrollBy方法來實現界面的滾動,可是這兩種滾動都是即刻瞬間的,對於用戶來講是不友好的,這個時候就須要一個滾動器來拉長這個滾動過程。也就是咱們的Scroller,這個滾動器的構造方法須要一個durration來設置滾動時間。canvas

Scroller的做用的是什麼?ide

實際上Scroller並不負責界面的實際滾動,雖然這個名字讓人誤解,但實際上它就是一個工具類,它有兩個最重要的方法,一個是startScroll(),這個方法就是根據scroller的構造方法中的x,y,distance,durration這些個參數來初始化一些參數,看源碼,和個人註釋,沒必要多言:工具

方法一:ui

    /**
     * Start scrolling by providing a starting point and the distance to travel.
     * 
     * @param startX Starting horizontal scroll offset in pixels. Positive
     *        numbers will scroll the content to the left.
     * @param startY Starting vertical scroll offset in pixels. Positive numbers
     *        will scroll the content up.
     * @param dx Horizontal distance to travel. Positive numbers will scroll the
     *        content to the left.
     * @param dy Vertical distance to travel. Positive numbers will scroll the
     *        content up.
     * @param duration Duration of the scroll in milliseconds.
     */
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {this

      //滾動模式標籤
        mMode = SCROLL_MODE;.net

      //滾動是否介紹,滾動到終點時這個值纔會爲真
        mFinished = false;設計

      //滾動時間
        mDuration = duration;code

       //起始時間
        mStartTime = AnimationUtils.currentAnimationTimeMillis();
        mStartX = startX;
        mStartY = startY;ip

       //重點橫座標=起點座標與distance的和
        mFinalX = startX + dx;
        mFinalY = startY + dy;
        mDeltaX = dx;
        mDeltaY = dy;

       //持續時間的一個倒數,後面更新滾動後的座標
        mDurationReciprocal = 1.0f / (float) mDuration;
    }

 

方法二:

 /**
     * Call this when you want to know the new location.  If it returns true,
     * the animation is not yet finished.  loc will be altered to provide the
     * new location.
     */ 
    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);
                final float t_inf = (float) index / NB_SAMPLES;
                final float t_sup = (float) (index + 1) / NB_SAMPLES;
                final float d_inf = SPLINE[index];
                final float d_sup = SPLINE[index + 1];
                final float distanceCoef = d_inf + (t - t_inf) / (t_sup - t_inf) * (d_sup - d_inf);
                
                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;
    }
    

這個方法無需多言,也是更新mCurrY 等狀態值。

綜上所述,scroller這個類就是一個工具類,get,set一些方法罷了,並不能幫助咱們滾動。

 

 

如何實現滾動?

android View類的scrollTo()方法結合Scroller一塊兒使用。具體就是View初始化的時候startScroll,而後去實現每個ViewGroup中都要實現的一個computeScroll方法,這個方法纔是真正控制滾動的方法。咱們只須要在咱們的ViewGroup中調用這兩個方法便可。具體就是copumteScroll中

     if (mScroller.computeScrollOffset()) {//爲true的時候說明沒有滾動到終點
            if (getScrollX() != mScroller.getCurrX()) {
                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            }
            invalidate();//scrollTo會致使界面刷新,invalidate()會再一次刷新,這樣會造成一個不間斷刷新過程
        }

View調用computeScroll的原理及過程?

View draw(Canvas can)有6個過程:

1.繪製bg  

2.保存一些Canvas的layer的狀態,爲橫豎的fadding edge繪製作準備

3.繪製content,也就是調用OnDraw方法來調用View具體的繪圖實現。

4.繪製childView,這個是針對ViewGroup的,在View中這個是一個空方法,在ViewGroup中的這個方法中會調用drawChild這個方法,這個方法就會調用computeScroll方法,實現滾動。

5..恢復canvas 的layer狀態,繪製fadding edge,

6.繪製scrollBar)

相關文章
相關標籤/搜索