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的程式碼
viewGroup的程式碼
viewGroup2的程式碼
view的程式碼
3.打log,看規律,識機制
預設情況下,這些方法都是return super(即父類的預設實現的)。所以先看一下預設情況下,一個ACTION_DOWN事件是怎麼傳遞的。給最裡面的View一個觸控,產生ACTION_DOWN事件。
- log:
- 可以看到傳遞流程,可以用流程圖表示為:
- log:
然後我們探索dispatchTouchEvent()方法,令其return false(這裡以ViewGroup2的dispatchTouchEvent()方法為例),log如下:
- log:
- 可以看到傳遞流程,可以用流程圖表示為:
- 規律:當dispatchTouchEvent()返回false時,會將事件傳遞給上一級的View的onTouchEvent()方法處理。由於Activity已經沒有比它更高一級的View,所以如果是Activity的dispatchTouchEvent()方法return false的話,事件會直接被消費掉(即終止傳遞)
- log:
接著讓dispatchTouchEvent()方法return true(這裡以ViewGroup2的dispatchTouchEvent()方法為例),log如下:
- log:
- 可以看到傳遞流程,可以用流程圖表示為:
- 規律:如果dispatchTouchEvent()方法返回true時,事件會被消費掉,不再傳遞。
- log:
然後我們探索一下onTouchEvent()方法,令其return false,(這裡以最裡層的View的onTouchEvent()方法為例),log如下:
- log:
- 可以看到傳遞流程,可以用流程圖表示為:
- 規律:如果onTouchEvent()方法返回false時,跟預設return super是一樣的,都會一直向上傳遞到上一級view的onTouchEvent()方法。
- 事實上,onTouchEvent()方法super父類的預設實現返回的就是false,所以是一樣的。關於原始碼的分析,請詳見《一步步探索學習Android Touch事件分發傳遞機制(三)》。
- log:
然後我們讓onTouchEvent()方法return true,(這裡以最裡層的View的onTouchEvent()方法為例),log如下:
- log:
- 可以看到傳遞流程,可以用流程圖表示為:
- 規律:如果onTouchEvent()方法返回true時,事件會被消費掉,不再傳遞。跟dispatchTouchEvent()return true的時候類似。
- log:
最後,我們來探索onInterceptTouchEvent()方法,令其return false,(這裡以最裡層的ViewGroup2的onInterceptTouchEvent()方法為例),log如下:
- log:
- 規律:這裡就不貼流程圖了,但是可以看到onInterceptTouchEvent()方法return false和return super是一樣的。都是預設將觸控事件傳給下一級view的dispatchTouchEvent()方法。
- 事實上,onInterceptTouchEvent()方法super父類的預設實現返回的就是false,所以是一樣的。關於原始碼的分析,請詳見《一步步探索學習Android Touch事件分發傳遞機制(三)》。
- log:
最後,我們讓onInterceptTouchEvent()方法return true,(這裡以最裡層的ViewGroup2的onInterceptTouchEvent()方法為例),log如下:
- log:
- 可以看到傳遞流程,可以用流程圖表示為:
- 規律:如果onInterceptTouchEvent()方法返回true時,Touch事件會被直接傳遞給ViewGroup自己的onTouchEvent()方法處理。
- log:
吾日三省吾身-- --總結歸納
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就可以實現觸控事件攔截。