在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類大體的使用和介紹已經完畢,之後會放上自己調用類實現的幾個漂亮的效果。