天天看點

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

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.界面&代碼
  • 一步步探索學習Android Touch事件分發傳遞機制(一)
  • 如上圖,可以看到,我在Activity裡面寫了三個View(ViewGroup)。ViewGroup1包裹着ViewGroup2,ViewGroup2包裹着一個TextView。這些View都是我自定義的。
  • 代碼部分就隻是重寫他們的dispatchTouchEvent();onInterceptTouchEvent()和onTouchEvent方法,傳回不同的值,列印log,看整個事件的傳遞流程。
    注:隻有ViewGroup有onInterceptTouchEvent()方法。至于為什麼這麼設計,在後面探索完之後會交代。
2.view的代碼
  • activity的代碼
    一步步探索學習Android Touch事件分發傳遞機制(一)
  • viewGroup的代碼
    一步步探索學習Android Touch事件分發傳遞機制(一)
  • viewGroup2的代碼
    一步步探索學習Android Touch事件分發傳遞機制(一)
  • view的代碼
    一步步探索學習Android Touch事件分發傳遞機制(一)
3.打log,看規律,識機制
  • 預設情況下,這些方法都是return super(即父類的預設實作的)。是以先看一下預設情況下,一個ACTION_DOWN事件是怎麼傳遞的。給最裡面的View一個觸摸,産生ACTION_DOWN事件。
    • log:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 可以看到傳遞流程,可以用流程圖表示為:
      一步步探索學習Android Touch事件分發傳遞機制(一)
  • 然後我們探索dispatchTouchEvent()方法,令其return false(這裡以ViewGroup2的dispatchTouchEvent()方法為例),log如下:
    • log:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 可以看到傳遞流程,可以用流程圖表示為:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 規律:當dispatchTouchEvent()傳回false時,會将事件傳遞給上一級的View的onTouchEvent()方法處理。由于Activity已經沒有比它更高一級的View,是以如果是Activity的dispatchTouchEvent()方法return false的話,事件會直接被消費掉(即終止傳遞)
  • 接着讓dispatchTouchEvent()方法return true(這裡以ViewGroup2的dispatchTouchEvent()方法為例),log如下:
    • log:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 可以看到傳遞流程,可以用流程圖表示為:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 規律:如果dispatchTouchEvent()方法傳回true時,事件會被消費掉,不再傳遞。
  • 然後我們探索一下onTouchEvent()方法,令其return false,(這裡以最裡層的View的onTouchEvent()方法為例),log如下:
    • log:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 可以看到傳遞流程,可以用流程圖表示為:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 規律:如果onTouchEvent()方法傳回false時,跟預設return super是一樣的,都會一直向上傳遞到上一級view的onTouchEvent()方法。
    • 事實上,onTouchEvent()方法super父類的預設實作傳回的就是false,是以是一樣的。關于源碼的分析,請詳見《一步步探索學習Android Touch事件分發傳遞機制(三)》。
  • 然後我們讓onTouchEvent()方法return true,(這裡以最裡層的View的onTouchEvent()方法為例),log如下:
    • log:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 可以看到傳遞流程,可以用流程圖表示為:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 規律:如果onTouchEvent()方法傳回true時,事件會被消費掉,不再傳遞。跟dispatchTouchEvent()return true的時候類似。
  • 最後,我們來探索onInterceptTouchEvent()方法,令其return false,(這裡以最裡層的ViewGroup2的onInterceptTouchEvent()方法為例),log如下:
    • log:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 規律:這裡就不貼流程圖了,但是可以看到onInterceptTouchEvent()方法return false和return super是一樣的。都是預設将觸摸事件傳給下一級view的dispatchTouchEvent()方法。
    • 事實上,onInterceptTouchEvent()方法super父類的預設實作傳回的就是false,是以是一樣的。關于源碼的分析,請詳見《一步步探索學習Android Touch事件分發傳遞機制(三)》。
  • 最後,我們讓onInterceptTouchEvent()方法return true,(這裡以最裡層的ViewGroup2的onInterceptTouchEvent()方法為例),log如下:
    • log:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 可以看到傳遞流程,可以用流程圖表示為:
      一步步探索學習Android Touch事件分發傳遞機制(一)
    • 規律:如果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()。
  • 回到之前我們的一個問題,為什麼隻有ViewGroup有onInterceptTouchEvent()方法呢,從上面的整個觸摸事件分發傳遞機制我們可以發現,ViewGroup本身的dispatchTouchEvent()方法無論傳回什麼都不能将事件傳遞給自己的onTouchEvent()方法處理,那就隻好設計了一個這樣子的方法,作為攔截器,攔截事件交給自己處理了。隻要onInterceptTouchEvent()return true就可以實作觸摸事件攔截。