《Android開發藝術探索》——View事件體系

QSNLin 7年前發布 | 6K 次閱讀 安卓開發 Android開發 移動開發

自定義控件、滑動沖突解決

View基礎知識

  1. View的位置參數
  2. MotionEvent和TouchSlop對象
  3. VelocityTracker
  4. GestureDetector和Scroller對象

1. View的位置參數

2. MotionEvent和TouchSlop

注意:各個方法相對目標不一樣。

view獲取自身坐標:getLeft(),getTop(),getRight(),getBottom()

view獲取自身寬高:getHeight(),getWidth()

motionEvent獲取坐標:getX(),getY(),getRawX(),getRawY()

  • MotionEvent
    Touch事件中,典型的事件有如下幾種:
    • ACTION_DOWN —— 手指接觸屏幕
    • ACTION_MOVE —— 手指在屏幕上移動
    • ACTION_UP —— 手指從屏幕離開
  • TouchSlop
    TouchSlop是系統所能識別出的被認為是滑動的最小距離,換句話說,當手指在屏幕上滑動時,當兩次滑動之間的距離小于這個常量,那么系統不認為是在進行滑動操作。通過以下方式獲取這個常量值:
    ViewConfiguration.get(getContext()).getScaledTouchSlop();
    這個常量有神馬意義呢?
    可以使用這個常量判斷是否達到滑動條件,處理滑動時,做一些過濾。

3. VelocityTracker、GestureDetector和Scroller對象

  • VelocityTracker
    速度追蹤,用于追蹤手指在滑動過程中的速度,包括水平和豎直方向的速度。
    構造方法中初始化獲取VelocityTracker對象
    VelocityTracker mVelocityTracker = VelocityTracker.obtain();
    onTouchEvent 方法中添加追蹤事件
    mVelocityTracker.addMovement(event);
    ACTION_UP 事件中獲取當前的速度。注意這里計算的是1000ms時間間隔移動的像素值,假設像素是100,即速度是每秒100像素。手指從右向左滑動,速度為負值。
    mVelocityTracker.computeCurrentVelocity(1000);
    float xVelocity = mVelocityTracker.getXVelocity();
    float yVelocity = mVelocityTracker.getYVelocity();
    最后,當不需要它的時候需要調用 clear 方法來重置并回收內存。
    mVelocityTracker.clear();
    mVelocityTracker.recycle();
  • GestureDetecor

    手勢檢測,用于輔助檢測用戶的單擊、滑動、長按、雙擊等行為。

    創建一個 GestureDetecor 對象并實現 OnGestureListener 接口,根據需要實現單擊等方法:

    GestureDetector mGestureDetector = new GestureDetector(this);
    // 解決長按屏幕后無法拖動的現象
    mGestureDetector.setIsLongpressEnabled(false);

    接管目標 ViewonTouchEvent 方法,在待監聽 ViewonTouchEvent 方法中添加如下實現:

    boolean consume = mGestureDetector.onTouchEvent(event);
    return consume;

    建議:

    如果只是監聽滑動操作,建議在onTouchEvent中實現;如果要監聽雙擊這種行為,則使用GestureDetector 。

  • Scroller
    彈性滑動對象,用于實現View的彈性滑動。
    View的scrollTo/scrollBy方法來滑動時,過程是瞬間完成的。使用Scroller則有過渡滑動的效果。注意,Scoller本身無法讓View彈性滑動,它需要和View的computerScroller方法配合使用。
    構造方法初始化
    Scroller mScroller = new Scroller(getContext());
    緩慢滑動到指定位置,一般在ACTION_UP 方法中執行,松手回彈效果。
    private void smoothScrollBy(int dx, int dy) {
      mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
      invalidate();
    }
    @Override
    public void computeScroll() {
      if (mScroller.computeScrollOffset()) {
          scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
          postInvalidate();
      }
    }
    Scroller原理

原理圖

當在MotionEvent.ACTION_UP事件觸發時,調用startScroll方法,并調用invalidate/postInvalidate方法,會導致View重繪,執行View.draw方法。在此方法中會調用View.computeScroll方法,此方法是空實現,需要我們自己處理邏輯。具體邏輯是:先判斷computeScrollOffset,如果為true,表示滾動未結束。則執行scrollTo方法,再次調用postInvalidate,如此反復執行,直到結束。

computeScrollOffset方法計算了一小段時間間隔內偏移的距離,即CurrX,CurrY。并返回是否滾動結束的標記。true表示未結束,false表示結束。

View的scrollTo/scrollBy方法操作的View的內容滑動。

getScrollX返回的是View的左邊緣到其內容左邊緣的距離。相對于View的左邊緣

getScrollY返回的是View的上邊緣到其內容上邊緣的距離。

如果View的內容向左滑,滑出View的左邊界,getScrollX為正值,反之為負值。

如果View的內容向上滑,滑出View的上邊界,getScrollY為正值,反之為負值。

getScrollX和getScrollY的變化示意圖

 

 

來自:http://www.jianshu.com/p/efcf275a7e00

 

 本文由用戶 QSNLin 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!