天天看點

Android 觸摸回報一些注意的點

之前在自定義View的那本書上就已經學習了 ​

​onTouchEvent()​

​​、​

​GestureDector​

​​。

因為觸摸回報的本質上就是在onTouchEvent/GestureDector去通過​​

​MotionEvent​

​做事件處理。,是以需要更細緻的去了解它們。是以這裡專門開了個小結。這篇學習完後,我将會寫一個可以縮放的自定義View。

是以在學習之前一定要搞懂View對事件的分發。

網上的學習blog很多。

這裡稍稍簡述一下:因為​

​事件Event​

​​是從在開始的 父View即Activity通過​

​dispatchTouchEvent​

​​往其子View傳,子View通過​

​onInterceptTouchEvent​

​​和​

​onTouchEvent​

​的傳回來判斷是否消費該事件,然後跟父View一樣做剩下的事情。如果直到最後的子View都不處理這個Event,則它會交給父View的onTouchEvent來處理,以此類推。

1、關于onTouchEvent的傳遞

是以一般情況下,onTouchEvent的傳遞是從我們點選的那個View開始處理,然後給它的父View… 如下圖所示:

Android 觸摸回報一些注意的點

上圖中,灰色是一個螢幕,手指點選的地方是螢幕的最前方,Activity相當已經是快要貼近螢幕背面了, 子View1和 子View2是重疊的,子View3不與他們重疊,一個使用者點選到了子View1和子View2重疊的地方,那麼一個onTouchEvent的對MotionEvent的傳遞就是 子View1 --> 子View2 -->Activity。

當然了,這是在考慮到 ​

​onInterceptTouchEvent()和dispatchTouchEvent​

​都走正常順序的情況下。隻是這樣畫圖更容易了解我們對事件的分發。

如果子View在onTouchEvent中傳回了true,就是說明子View1消費了該事件序列,從DOWN一直到 UP/CANCEL的所有event全都由該View的 onTouchEvent()來解決

注意:隻有對DOWN 傳回了true,那麼之後 如果對該View的其他接到的event傳回false,這系列的事件都不會傳下去,而是還是在該View裡面。

2、getAction()和getActionMasked()的差別:

  • ​getActionMasked()​

    ​解決了多點觸控,是比較晚api出的,而getAction()則最開始更多的考慮的是單點觸控
  • 如果隻是對 UP/DOWN/MOVE等這些比較普通的做操作,那麼兩者在性能上是沒有差別的
  • ​getActionMasked()​

    ​​主要是在對​

    ​POINTER_DOWN​

    ​​/​

    ​POINTER_UP​

    ​有不同與getAction的處理。

看過onTouchEvent源碼的都知道,就是對 點選、長按、右鍵點選做預處理和處理而已。

3、onInterceptTouchEvent()一些注意的點:

  • 一般出現了重寫這個方法的情況,就說明目前界面需要處理滑動沖突!
  • ​onInterceptTouchEvent()​

    ​​隻能在ViewGroup中重寫,并且重寫了該方法後,就也要重寫這個ViewGroup的​

    ​onTouchEvent()​

    ​(因為這就是應對滑動沖突的問題)

4、dispatchTouchEvent()一些注意的點:

  • 當在使用者第一次按下的時候(即産生了ACTION_DOWN時),會清空​

    ​TouchTargets​

    ​​(這個用于多點觸控記錄目标View)和​

    ​DISALLOW_INTERCEPT​

    ​(比如在滑動ViewPage時,我們想橫向滑動,但是在開始的幾百毫秒内,可能會産生縱向滑動大于橫向滑動,就會走很縱向滑動的邏輯,這顯然不是我們想要的,是以這個時候就不會攔截,這個标記位就是這麼一個作用。)
  • 如果不攔截并且不是CANCEL,并且是DOWN或者是POINTER_DOWN,會嘗試把pointer通過​

    ​TouchTarget​

    ​配置設定給 子View
  • TouchTargets是用來記錄螢幕被那幾個手指按下了,其結構是一個單向連結清單。
  • 父View會先看看有沒有TouchTarget,如果沒有就調用自己的super.dispatchTouchEvent(),否則,就調用child.dispatchTouchEvent()
  • 如果是POINTER_UP,就要去TouchTargets中清除POINTER資訊,如果是UP或者CANCEL,就重置狀态。
  1. ACTION_UP永遠是事件序列最後出現的

    一組MotionEvent事件不是對應一個手指的,而是對應一個View的,之是以這樣說,是因為有些人會在多點觸控下搞迷糊了。比如看這麼一個順序(注意:都是按在統一個View) : 手指1按下->手指2按下->手指1擡起->手指2擡起

    會有人可能覺得順序時 DOWN->POINTER_DOWN->UP->POINTER_UP,但其實是錯的;

    實際上應該是 DOWN->POINTER_DOWN->POINTER_UP->UP

  2. ​activePointer​

    ​​ 每次按下一個手指,就會産生一個​

    ​activiePointer(x,y,index:x)​

    ​,可以通過getActionIndex來擷取該pointer的index,每個pointer也有對應的​

    ​pointerId​

    ​,而我們對于多手指的操控,就是通過 ​

    ​pointerId​

    ​和​

    ​index​

    ​做判斷。

    比如我們擷取了一個手指的index = 1,那麼後面我們如果要擷取該手指的位置,我們可以用 getX(1)

    但是他們并不是順序的,比如你三指操作的時候,一開始時index = 0、1、2,後來拿掉了中間一根,可能就變成了 0、1或者0、2甚至1、2,是以我們每次都要去擷取其index

  3. ACTION_MOVE表示有手指發生移動,而不是某一個手指發生了移動
  4. 在該View産生的MotionEvent是針對于該View的

    多點觸控,如果觸摸了兩個View,那麼通過滑動沖突,先攔截事件的那個View擷取了後續所有的 隻在該View産生的事件序列(重點)。

繼續閱讀