Android 介面滑動實現---Scroller類 從源碼和開發文檔中學習(讓你的布局動起來)

來源:互聯網
上載者:User

在android學習中,動作互動是軟體中重要的一部分,其中的Scroller就是提供了拖動效果的類,在網上,比如說一些Launcher實現滑屏都可以通過這個類去實現。。
在廣泛使用的側邊滑動導航開源庫 --SlidingLayer其實就是使用到了Scroller類進行的實現,:GITHUB ,下面要講的不是這個庫,而是這個庫的實現過程中使用到的---Scroller類,懂了之後你看庫的源碼就知道,原來它是這樣實現的。


Scroller類使用過程中,懂得以下機制可能會對開發更有協助:
1.視圖的VIEW的自訂以及其在螢幕中布局。
2.scrollTo()和scrollBy()方法的作用區別 可以點擊此處瞭解:android 布局之滑動探究 scrollTo 和 scrollBy 方法使用說明
3.螢幕中的觸摸事件分發機制(這一塊在涉及到觸摸的任何情況下都十分重要)


首先看看發開文檔裡面說了些什麼:android發開文檔
開發文檔參考連結:http://developer.android.com喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcmVmZXJlbmNlL2FuZHJvaWQvd2lkZ2V0L1Njcm9sbGVyLmh0bWwKCjxoMT5TY3JvbGxlcjwvaDE+CgoKPGgyPtK7Lr3hubm52M+1PC9oMj4KCmV4dGVuZHMgT2JqZWN0Cjxicj4KCgo8aDI+tv4uuMXK9jwvaDI+CgoKPGgyPkNsYXNzIE92ZXJ2aWV3PC9oMj4KPGhyPgo8cD4KVGhpcyBjbGFzcyBlbmNhcHN1bGF0ZXMgc2Nyb2xsaW5nLiBZb3UgY2FuIHVzZSBzY3JvbGxlcnMgKDxjb2RlPlNjcm9sbGVyPC9jb2RlPiBvciA8Y29kZT5PdmVyU2Nyb2xsZXI8L2NvZGU+KQogdG8gY29sbGVjdCB0aGUgZGF0YSB5b3UgbmVlZCB0byBwcm9kdWNlIGEgc2Nyb2xsaW5nIGFuaW1hdGlvbqGqZm9yIGV4YW1wbGUsIGluIHJlc3BvbnNlIHRvIGEgZmxpbmcgZ2VzdHVyZS4gU2Nyb2xsZXJzIHRyYWNrIHNjcm9sbCBvZmZzZXRzIGZvciB5b3Ugb3ZlciB0aW1lLCBidXQgdGhleSBkb24="t automatically apply those positions to your view. It's your responsibility to get and apply new coordinates at a rate that will make the scrolling animation look smooth.


這個類封裝了滾動操作,你可以根據你的手勢對介面進行更加平滑的滾動操作。

To track the changing positions of the x/y coordinates, use computeScrollOffset(). The method returns a boolean to indicate whether the scroller is finished. If it isn't, it means that a fling or programmatic pan operation is still in progress. You can use this method to find the current offsets of the x and y coordinates, for example:


跟蹤變化的x / y座標的位置,通過computeScrollOffset()方法監聽返回的布爾值來指示滾動動作是否完成。如果返回為false,說明滾動已經結束。返回true,它意味著操作仍在進行中。您可以使用

int currX = mScroller.getCurrX(); //滾動的X滾動距離

int currY = mScroller.getCurrY(); //滾動的y滾動距離

這個方法來找到當前的x和y座標的位移量。


三.建構函式
Public Constructors

Scroller(Context context)Create a Scroller with the default duration and interpolator.

Scroller(Context context, Interpolator interpolator)Create a Scroller with the specified interpolator.

Scroller(Context context, Interpolator interpolator, boolean flywheel)Create a Scroller with the specified interpolator.

Interpolator interpolator 表示的是動畫插入器,你可以設定相應的效果給它。


Interpolator

implements TimeInterpolator

android.view.animation.Interpolator

Known Indirect Subclasses

AccelerateDecelerateInterpolator, AccelerateInterpolator, AnticipateInterpolator, AnticipateOvershootInterpolator, BounceInterpolator, CycleInterpolator,DecelerateInterpolator, LinearInterpolator, OvershootInterpolator


AccelerateDecelerateInterpolator 動畫效果:開始和結束都是緩慢的,通過中間時候加速

AccelerateInterpolator, 動畫效果:開始緩慢,之後加速

AnticipateInterpolator, 動畫效果:開始後退,然後前進

AnticipateOvershootInterpolator, 動畫效果:開始後退,之後前進並超過終點位置,最終退回到終點

BounceInterpolator, 動畫效果:慢慢反彈到,彈性衰減到結束

CycleInterpolator, 動畫效果:重複迴圈動畫,速度變化遵循正弦定律

DecelerateInterpolator, 動畫效果:剛開始快速,之後減速

LinearInterpolator, 動畫效果:不斷的變化

OvershootInterpolator 動畫效果:像前超越最終點然後回來


可以通過初始化構造方法Scroller(Context context, Interpolator interpolator)給它相應的動畫效果。

Interpolator interpolator = new BounceInterpolator();


四.公用方法

Public Methods
void abortAnimation() 停止動畫,滾到最終的x,y位置中止動畫
boolean computeScrollOffset() 當你想要知道新的位置時候,調用該方法。返回true:動畫沒結束
void extendDuration(int extend) 延長滾動動畫的時間。extend表示延遲時間(單位為毫秒)
void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY)在fling(快速滑動,觸控螢幕幕後快意移動鬆開)的手勢基礎上開始滾動,滾動距離取決於fling的初速度。
final void forceFinished(boolean finished) 強制終止滾動。
float getCurrVelocity() 返回當前的速度
final int getCurrX() 返回當前滾動的X方向的位移量(距離原點X軸方向)
final int getCurrY() 返回當前滾動的Y方向的位移量(距離原點Y軸方向)
final int getDuration() 返復原動事件的期間(毫秒)
final int getFinalX() 返復原動結束的X方向的位移量(註:只針對fling 手勢有效)(距離原點X軸方向)
final int getFinalY() 返復原動結束的Y方向的位移量(註:只針對fling 手勢有效)(距離原點Y軸方向)
final int getStartX() 返復原動起始點的X方向位移量(距離原點X軸方向)
final int getStartY() 返復原動起始點的Y方向位移量.(距離原點Y軸方向)
final boolean isFinished() 返回scroller滾動是否結束,true:滾動結束 false:還在滾動
void setFinalX(int newX) 設定scroller的終止時X方向位移量
void setFinalY(int newY) 設定scroller的終止時Y方向位移量
final void setFriction(float friction)The amount of friction applied to flings.
void startScroll(int startX, int startY, int dx, int dy)提供起始點和滾動距離,調用該方法進行滾動。(此處預設時間為250ms)
void startScroll(int startX, int startY, int dx, int dy, int duration)提供起始點和滾動距離以及滾動時間,調用該方法進行滾動。
int timePassed() 返回自滾動開始經過的時間(毫秒)


源碼

下面看看以上方法的源碼實現:

知識點1:computeScrollOffset()方法

 /**     * 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; //已經完成了本次動畫,直接返回為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;    }

調用該方法判斷滾動是否還在繼續,mFinished屬性判斷是否滾動完成,如果滾動完成了,mFinished = true,computeScrollOffset() 返回false。


知識點2:computeScroll()方法

    /**     * Called by a parent to request that a child update its values for mScrollX     * and mScrollY if necessary. This will typically be done if the child is     * animating a scroll using a {@link android.widget.Scroller Scroller}     * object.     */由父視圖調用用來請求子視圖根據位移值 mScrollX,mScrollY重新繪製      public void computeScroll() {    }

知道了computeScrollOffset()這個判斷是否滾動的方法,那我們必須要有監聽滑屏控制,並且重繪,在Android架構中的VIEW類中就提供了computeScroll()這個方法去控制該流程。在繪製View時,會在draw()程序呼叫該方法。因此, 再配合使用Scroller執行個體,我們就可以獲得當前應該的位移座標,手動使View/ViewGroup位移至該處。

註:在使用Scroller這個類實現位移控制,一般自訂View/ViewGroup都需要重載該方法 。

具體實現:

@Overridepublic void computeScroll() {if (mScroller.computeScrollOffset()) {scrollTo(mScroller.getCurrX(), mScroller.getCurrY());// 更新介面postInvalidate();isMoving = true;} else {isMoving = false;}super.computeScroll();}


知識點3:startScroll()方法
 /**     * Start scrolling by providing a starting point and the distance to travel.     *     * @param startX  //水平方向滾動的位移值,以像素為單位。正值表明滾動將向左滾動     * @param startY  //垂直方向滾動的位移值,以像素為單位。正值表明滾動將向上滾動     * @param dx //水平方向滑動的距離,正值會使滾動向左滾動     * @param dy //垂直方向滑動的距離,正值會使滾動向上滾動     * @param duration //滾動期間     */    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;    }

該方法以提供的起始點和將要滑動的距離開始滾動,我們可以使用該方法達到自動滾動的效果。在滾動中,如果符合什麼條件,可以調用該方法讓它滾動到相對應的地方。


著重點:

在介面滾動中,你必須搞清楚和scrollTo和scrollBy之間的區別所在:android 布局之滑動探究 scrollTo 和 scrollBy 方法使用說明


需要注意的是,移動的時候向左移動為負,向下移為負。如下:


使用思路流程:

如果你使用Scroller,流程如下:

1.可以在自訂的布局中,按照需求初始化Scroller建構函式。

2.重寫onInterceptTouchEvent(MotionEvent ev)方法,看看是否要攔截相關的點擊時間。

3.重寫onTouchEvent(MotionEvent event)方法,根據觸控螢幕上的動作使用computeScroll()以及scrollTo 和 scrollBy 方法進行根據手指對布局進行滑動效果。

4.在觸摸操作結束(MotionEvent.ACTION_UP)的時候,調用startScroll(int startX, int startY, int dx, int dy, int duration)方法,進行動畫自動操作,來完成整個滾動流程。


對於Scroller類大體的使用和介紹已經完畢,之後會放上自己調用類實現的幾個漂亮的效果。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.