一步步探索學習Android Touch事件分發傳遞機制(一)

小莫Alan_Mo發表於2017-11-18

Android TouchEvent 簡介

1.探究物件簡介
  • Android的螢幕觸控事件在Android官方API中由類MotionEvent來描述,不同的觸控事件對應不同的事件型別。
  • 如:ACTION_DOWN;ACTION_UP;ACTION_MOVE;ACTION_CANCEL
  • 每個事件對應都有自己的傳遞路徑,從產生到傳遞到最終被消費(終止傳遞)。而它們的傳遞的載體就是整顆View樹。
  • 畢竟這是螢幕觸控事件,而螢幕上顯示的正是由不同的ViewGroup和各式各樣的View組成的View樹。
  • 我們需要探索的就是一個TouchEvent的整個從產生到被消費的整個傳遞過程和機制。
  • 裡面我們核心需要探索的是關於View和ViewGroup類中的以下幾個處理觸控事件的方法的處理流程。

    ViewGoup: dispatchTouchEvent(); onInterceptTouchEvent(); onTouchEvent()
    View:dispatchTouchEvent(); onTouchEvent()
    Activity:dispatchTouchEvent(); onTouchEvent()

    2.探索Touch事件的傳遞機制的意義
  • 通過了解和探究Android Touch事件的傳遞機制,可以讓我們明白觸控事件到底是怎麼產生以及如何被處理的

  • 可以在此基礎上深刻的清楚整個View樹處理觸控事件的流程,從而對我們如何避免觸控事件衝突,點選事件攔截等業務開發需求時,做到胸有成竹。
    -像我們平時常遇到的一些自定義View巢狀時點選事件,觸控手勢衝突的問題的解決都依賴於我們對這個機制的認識。

說明:
1.為了便於理解和整文的清晰明瞭,本篇文章只是分析一種事件型別:ACTION_DOWN事件的傳遞過程,置於ACTION_MOVE,ACTION_UP事件會在下一篇文章《一步步探索學習Android Touch事件分發傳遞機制(二)》中分析
2.知其然,還須知其所以然,我會在《一步步探索學習Android Touch事件分發傳遞機制(三)》中,通過分析Android原始碼來解釋探索整個Android Touch事件傳遞分發機制。

寫個Demo去探索

  • 廢話不多說,“絕知此事要躬行”,所以直接寫個Demo打log出來看,其實這個機制會很清晰明瞭。
  • 各位看官,看log,找規律!
1.介面&程式碼
  • 這裡寫圖片描述
    這裡寫圖片描述

  • 如上圖,可以看到,我在Activity裡面寫了三個View(ViewGroup)。ViewGroup1包裹著ViewGroup2,ViewGroup2包裹著一個TextView。這些View都是我自定義的。

  • 程式碼部分就只是重寫他們的dispatchTouchEvent();onInterceptTouchEvent()和onTouchEvent方法,返回不同的值,列印log,看整個事件的傳遞流程。

    注:只有ViewGroup有onInterceptTouchEvent()方法。至於為什麼這麼設計,在後面探索完之後會交代。

2.view的程式碼
  • activity的程式碼

    activity的程式碼
    activity的程式碼

  • viewGroup的程式碼

    viewGroup的程式碼
    viewGroup的程式碼

  • viewGroup2的程式碼

    viewGroup2的程式碼
    viewGroup2的程式碼

  • view的程式碼

    view的程式碼
    view的程式碼

3.打log,看規律,識機制
  • 預設情況下,這些方法都是return super(即父類的預設實現的)。所以先看一下預設情況下,一個ACTION_DOWN事件是怎麼傳遞的。給最裡面的View一個觸控,產生ACTION_DOWN事件。

    • log:
      這裡寫圖片描述
      這裡寫圖片描述
    • 可以看到傳遞流程,可以用流程圖表示為:
      類U型Touch事件傳遞機制
      類U型Touch事件傳遞機制
  • 然後我們探索dispatchTouchEvent()方法,令其return false(這裡以ViewGroup2的dispatchTouchEvent()方法為例),log如下:

    • log:
      這裡寫圖片描述
      這裡寫圖片描述
    • 可以看到傳遞流程,可以用流程圖表示為:
      這裡寫圖片描述
      這裡寫圖片描述
    • 規律:當dispatchTouchEvent()返回false時,會將事件傳遞給上一級的View的onTouchEvent()方法處理。由於Activity已經沒有比它更高一級的View,所以如果是Activity的dispatchTouchEvent()方法return false的話,事件會直接被消費掉(即終止傳遞)
  • 接著讓dispatchTouchEvent()方法return true(這裡以ViewGroup2的dispatchTouchEvent()方法為例),log如下:

    • log:
      這裡寫圖片描述
      這裡寫圖片描述
    • 可以看到傳遞流程,可以用流程圖表示為:
      這裡寫圖片描述
      這裡寫圖片描述
    • 規律:如果dispatchTouchEvent()方法返回true時,事件會被消費掉,不再傳遞。
  • 然後我們探索一下onTouchEvent()方法,令其return false,(這裡以最裡層的View的onTouchEvent()方法為例),log如下:

    • log:
      這裡寫圖片描述
      這裡寫圖片描述
    • 可以看到傳遞流程,可以用流程圖表示為:
      這裡寫圖片描述
      這裡寫圖片描述
    • 規律:如果onTouchEvent()方法返回false時,跟預設return super是一樣的,都會一直向上傳遞到上一級view的onTouchEvent()方法。
    • 事實上,onTouchEvent()方法super父類的預設實現返回的就是false,所以是一樣的。關於原始碼的分析,請詳見《一步步探索學習Android Touch事件分發傳遞機制(三)》。
  • 然後我們讓onTouchEvent()方法return true,(這裡以最裡層的View的onTouchEvent()方法為例),log如下:

    • log:
      這裡寫圖片描述
      這裡寫圖片描述
    • 可以看到傳遞流程,可以用流程圖表示為:
      這裡寫圖片描述
      這裡寫圖片描述
    • 規律:如果onTouchEvent()方法返回true時,事件會被消費掉,不再傳遞。跟dispatchTouchEvent()return true的時候類似。
  • 最後,我們來探索onInterceptTouchEvent()方法,令其return false,(這裡以最裡層的ViewGroup2的onInterceptTouchEvent()方法為例),log如下:

    • log:
      這裡寫圖片描述
      這裡寫圖片描述
    • 規律:這裡就不貼流程圖了,但是可以看到onInterceptTouchEvent()方法return false和return super是一樣的。都是預設將觸控事件傳給下一級view的dispatchTouchEvent()方法。
    • 事實上,onInterceptTouchEvent()方法super父類的預設實現返回的就是false,所以是一樣的。關於原始碼的分析,請詳見《一步步探索學習Android Touch事件分發傳遞機制(三)》。
  • 最後,我們讓onInterceptTouchEvent()方法return true,(這裡以最裡層的ViewGroup2的onInterceptTouchEvent()方法為例),log如下:

    • log:
      這裡寫圖片描述
      這裡寫圖片描述
    • 可以看到傳遞流程,可以用流程圖表示為:
      這裡寫圖片描述
      這裡寫圖片描述
    • 規律:如果onInterceptTouchEvent()方法返回true時,Touch事件會被直接傳遞給ViewGroup自己的onTouchEvent()方法處理。

吾日三省吾身-- --總結歸納

1.對於dispatchTouchEvent()方法:

  • return true:消費掉事件,終止傳遞。
  • return false: 將事件傳遞給上一級View的onTouchEvent()方法。如果是Activity的dispatchTouchEvent()方法,則也是消費掉事件,終止傳遞。
  • return super:如果是Activity,則傳給下一級view(viewGroup)的dispatchTouchEvent;如果是ViewGroup,則傳給自己的onInterceptTouchEvent();如果是View,則傳給自己的onTouchEvent().

2.對於onTouchEvent()方法:

  • return true:消費掉事件,終止傳遞。
  • return false/super:將事件傳遞給上一級view的onTouchEvent()方法。

3.對於onInterceptTouchEvent()方法:

  • return true:將事件傳遞給ViewGroup自己的onTouchEvent()方法處理。
  • return false/super:將事件傳遞給下一級View的dispatchTouchEvent()。
  • 回到之前我們的一個問題,為什麼只有ViewGrouponInterceptTouchEvent()方法呢,從上面的整個觸控事件分發傳遞機制我們可以發現,ViewGroup本身的dispatchTouchEvent()方法無論返回什麼都不能將事件傳遞給自己的onTouchEvent()方法處理,那就只好設計了一個這樣子的方法,作為攔截器,攔截事件交給自己處理了。只要onInterceptTouchEvent()return true就可以實現觸控事件攔截。

相關文章