Android開發——彈性滑動的兩種實現方式
0. 前言
我們在Android開發——View滑動的三種實現方式中學習瞭如何進行View滑動,在第一種方法,利用ScrollBy和ScrollTo進行滑動時,滑動效果是瞬間完成的,為了更好的使用者體驗,有時我們需要滑動有一個漸變的過程。這就是所謂的彈性滑動。
1. 延時策略
我們解決彈性滑動的第一反應可能就是採用延時策略,通過Handler傳送並接收延時訊息,每次接收到訊息便完成一次ScrollTo操作,從而實現彈性滑動的效果。核心程式碼展示如下:
public void handleMessage(Message msg) { switch(mag.what){ case SCROLL_FRACTION:{ //if判斷滑動還沒有結束,結束則不再滑動和傳送訊息 if(){ //通過滑動完成比例計算該次滑動片段的位置點scrollX,scrollY View.scrollTo(scrollX,scrollY); mHandler.sendEmptyMessageDelayed(SCROLL_FRACTION, 20); } break; } default: break; } }
上述這種利用Handler傳送延時訊息的方式比較簡單,但是需要注意的是,由於系統的訊息排程需要時間,完成這次彈性滑動的時間總是大於if條件判斷為true的次數乘以20ms(延遲訊息的傳送時間間隔)。
因此對彈性滑動完成總時間有精確要求的使用場景下,使用延時策略是一個不太合適的選擇。
2. Scroller的使用
2.1 系統提供的Scroller
利用系統提供給我們的Scroller類,我們可以很方便的實現彈性滑動。程式碼比較簡單,都是模版化的,如下所示:
Scroller scroller = new Scroller(mContext); private void smoothScrollTo(int destX, int destY){ int distanceX = destX - getScrollX(); int distanceY = destY - getScrollY(); //設定500ms的彈性滑動總時長 mScroller.startScroll(getScrollX(),getScrollY(),distanceX, distanceY, 500); //重繪 invalidate(); }
//該方法為空實現,因此需要重寫
//該方法會被invalidate()方法觸發執行
@override
public void computeScroll(){
//判斷滑動還沒有結束
if(mScroller.computeScrollOffset()){
//通過Scroller類拿到下一步要滑動到的位置
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
這裡說一下invalidate()和postInvalidate()的區別:
為了UI安全,invalidate()可在
2.2 自定義Scroller
上面介紹了呼叫系統提供的Scroller的使用方法,但是Scroller類的getCurrX()、computeScrollOffset()等方法都是寫死的。實現的彈性滑動是先快後慢的效果。
下面我們自行實現一個MyScroller類來完成勻速滑動的效果,同時也有助於理解系統Scroller類的實現原理。
/*
* Created by SEU_Calvin on 2016/09/12
* 計算位移距離的自定義Scroller
*/
public class MyScroll{
private int startX;
private int startY;
private int distanceX;
private int distanceY;
private int duration;
//開始執行動畫的時間
private long startTime;
//判斷是否動畫結束
private boolean isFinish;
//計算當前距離
private long currentX;
private long currentY;
public MyScroll(Context context) {
}
public long getCurrX() {
return currentX;
}
public long getCurrY() {
return currentY;
}
public void startScroll(int startX, int startY, int distanceX, int distanceY, int duration) {
this.startX = startX;
this.startY = startY;
this.distanceX = distanceX;
this.distanceY = distanceY;
this.duration = duration;
this.startTime = SystemClock.uptimeMillis();
this.isFinish = false;
}
/*
* Created by SEU_Calvin on 2016/09/12
* 判斷是否滑動結束並改變將要被使用的currentX/Y
*/
public boolean computeScrollOffset() {
if(isFinish){
return false;
}
//獲得startTime到呼叫由於重繪導致computeScrollOffset()呼叫之間的passtime
long passtime = SystemClock.uptimeMillis()-startTime;
//計算currentX的值,指導下一步ScrollTo的位置
//startX/Y <currentX/Y<= startX/Y + distanceX/Y
if(passtime<duration){
currentX = startX + distanceX*passtime/duration;
currentY = startY + distanceY*passtime/duration;
}else{
//執行結束
currentX = startX + distanceX;
currentY = startY + distanceY;
isFinish = true;
}
return true;
}
}
我們只要在呼叫時改變呼叫的MyScroll類即可。其他程式碼不做修改。
具體滑動效果,如勻速,勻加速,先慢後快等效果完全可以由MyScroll中自己的演算法來決定。
以上就是對Android開發中彈性滑動的介紹。