1. 程式人生 > >Android開發——彈性滑動的兩種實現方式

Android開發——彈性滑動的兩種實現方式

0. 前言

我們在Android開發——View滑動的三種實現方式中學習瞭如何進行View滑動,在第一種方法,利用ScrollByScrollTo進行滑動時,滑動效果是瞬間完成的,為了更好的使用者體驗,有時我們需要滑動有一個漸變的過程。這就是所謂的彈性滑動。

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()可在

主執行緒直接呼叫重新整理介面,而postInvalidate()會用Handler通知UI執行緒重繪螢幕,因此後者適用於子執行緒

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開發中彈性滑動的介紹。