事件的分发机制
事件分發機制
Android 編程下 Touch 事件的分發和消費機制
Android 中與 Touch 事件相關的方法包括:dispatchTouchEvent(MotionEvent ev)、onInterceptTouchEvent(MotionEvent ev)、onTouchEvent(MotionEvent ev);能夠響應這些方法的控件包括:ViewGroup 及其子類、Activity。方法與控件的對應關系如下表所示:
從這張表中我們可以看到 ViewGroup 及其子類對與 Touch 事件相關的三個方法均能響應,而 Activity 對 onInterceptTouchEvent(MotionEvent ev) 也就是事件攔截不進行響應。另外需要注意的是 View 對 dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev) 的響應的前提是可以向該 View 中添加子 View,如果當前的 View 已經是一個最小的單元 View(比如 TextView),那么就無法向這個最小 View 中添加子 View,也就無法向子 View 進行事件的分發和攔截,所以它沒有 dispatchTouchEvent(MotionEvent ev) 和 onInterceptTouchEvent(MotionEvent ev),只有 onTouchEvent(MotionEvent ev)。
一、Touch 事件分析
//自己寫的,有什么意見可以留言,希望和大家一起討論
當dispatchTouchEvent onInterceptTouchEvent onTouchEvent 三個方法都返回默認的super. 的時候,事件會一直傳遞的最終的子view控件上 觸發onClient事件 ? 事件分發:public boolean dispatchTouchEvent(MotionEvent ev) Touch 事件發生時 Activity 的?dispatchTouchEvent(MotionEvent ev) 方法會以隧道方式(從根元素依次往下傳遞直到最內層子元素或在中間某一元素中由于某一條件停止傳遞)將事件傳遞給最外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由該 View 的 dispatchTouchEvent(MotionEvent ev) 方法對事件進行分發。dispatchTouchEvent 的事件分發邏輯如下:
如果當前 View 獲取的事件直接來自 Activity,則會將事件返回給 Activity 的 onTouchEvent 進行消費;
摁下
03-26 19:51:34.319 17031-17031/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent
03-26 19:51:34.319 17031-17031/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent
抬起
03-26 19:51:34.319 17031-17031/com.example.my_event_fenfa D/Event: Activity ------- > onTouchEvent
03-26 19:51:37.199 17031-17031/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent
03-26 19:51:37.199 17031-17031/com.example.my_event_fenfa D/Event: Activity ------- > onTouchEvent
如果當前 View 獲取的事件來自外層父控件,則會將事件返回給父 View 的? onTouchEvent 進行消費。
這里我沒有試,如果方便的話 大家可以自己敲個Demo試一下
? 事件攔截:public boolean onInterceptTouchEvent(MotionEvent ev) 在外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系統默認的 super.dispatchTouchEvent(ev) 情況下,事件會自動的分發給當前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件攔截邏輯如下:
? 事件響應:public boolean onTouchEvent(MotionEvent ev) 在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 的情況下 onTouchEvent 會被調用。onTouchEvent 的事件響應邏輯如下:
最后呢 補充一個小知識點 onTouchEvent和onClick 一般情況下 onTouchEvent 會比Onclick 執行的早 而當你在onTouchEvent 返回值為true時 是不會執行onClick方法的 但是false也沒有執行 只有默認執行了
以下 是我打的Log 大家可以看下 同時也可以發表一下建議 一起討論 true是沒有執行onclick方法 摁下 03-26 20:40:37.309 26045-26045/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:40:37.309 26045-26045/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:40:37.309 26045-26045/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:40:37.309 26045-26045/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent 抬起 03-26 20:40:37.969 26045-26045/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:40:37.969 26045-26045/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:40:37.969 26045-26045/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:40:37.969 26045-26045/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent
false 也沒有執行onClick方法 摁下 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: LinearLayout ------- > onTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: Activity ------- > onTouchEvent 抬起 03-26 20:41:27.889 26643-26643/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:41:27.889 26643-26643/com.example.my_event_fenfa D/Event: Activity ------- > onTouchEvent
默認return super.onTouchEvent(event); 這里執行了onClient方法 摁下 03-26 20:43:04.919 28076-28076/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:43:04.919 28076-28076/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:43:04.919 28076-28076/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:43:04.919 28076-28076/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent 抬起 03-26 20:43:05.689 28076-28076/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:43:05.689 28076-28076/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:43:05.689 28076-28076/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:43:05.689 28076-28076/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent 03-26 20:43:05.699 28076-28076/com.example.my_event_fenfa D/Event: View ------- > onClick
| Touch 事件相關方法 | 方法功能 | ViewGroup | Activity |
| public boolean dispatchTouchEvent(MotionEvent ev) | 事件分發 | Yes | Yes |
| public boolean onInterceptTouchEvent(MotionEvent ev) | 事件攔截 | Yes | No |
| public boolean onTouchEvent(MotionEvent ev) | 事件響應 | Yes | Yes |
當dispatchTouchEvent onInterceptTouchEvent onTouchEvent 三個方法都返回默認的super. 的時候,事件會一直傳遞的最終的子view控件上 觸發onClient事件 ? 事件分發:public boolean dispatchTouchEvent(MotionEvent ev) Touch 事件發生時 Activity 的?dispatchTouchEvent(MotionEvent ev) 方法會以隧道方式(從根元素依次往下傳遞直到最內層子元素或在中間某一元素中由于某一條件停止傳遞)將事件傳遞給最外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由該 View 的 dispatchTouchEvent(MotionEvent ev) 方法對事件進行分發。dispatchTouchEvent 的事件分發邏輯如下:
- 如果 return true,事件會分發給當前 View 并由 dispatchTouchEvent 方法進行消費,同時事件會停止向下傳遞;
- 摁下
- 03-26 19:49:42.249 15512-15512/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent
- 如果 return false,事件分發分為兩種情況:
- 如果返回系統默認的 super.dispatchTouchEvent(ev),事件會自動的分發給當前 View 的 onInterceptTouchEvent 方法。
- 摁下
- 這里先不要注意打那么多Log,只要注意Demo走了當前View的onInterceptTouchEvent就可以了
- 03-26 19:54:41.659 18953-18953/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent
? 事件攔截:public boolean onInterceptTouchEvent(MotionEvent ev) 在外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系統默認的 super.dispatchTouchEvent(ev) 情況下,事件會自動的分發給當前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件攔截邏輯如下:
- 如果 onInterceptTouchEvent 返回 true,則表示將事件進行攔截,并將攔截到的事件交由當前 View 的 onTouchEvent 進行處理;
- 摁下
- 這里也不要在意那么多Log 只要看到事件走了當前View的onTouchEvent方法
- 03-26 20:00:09.319 24201-24201/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent
- 如果 onInterceptTouchEvent 返回 false,則表示將事件放行,當前 View 上的事件會被傳遞到子 View 上,再由子 View 的 dispatchTouchEvent 來開始這個事件的分發;
- 摁下
- 注意我這里在布局中只寫了一個TextView控件 所以事件會傳遞給TextView的onTouchEvent事件 而TextView是沒有攔截事件和分發事件 大家如果不滿意的話可以自己再加有個ListView試一下,這里我就不做過多步驟了
- 03-26 20:04:08.879 27684-27684/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent
- 如果 onInterceptTouchEvent 返回?super.onInterceptTouchEvent(ev),和false返回的結果一樣
? 事件響應:public boolean onTouchEvent(MotionEvent ev) 在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 的情況下 onTouchEvent 會被調用。onTouchEvent 的事件響應邏輯如下:
- 如果事件傳遞到當前 View 的 onTouchEvent 方法,而該方法返回了 false,那么這個事件會從當前 View 向上傳遞,并且都是由上層 View 的 onTouchEvent 來接收,如果傳遞到上面的 onTouchEvent 也返回 false,這個事件就會“消失”,而且接收不到下一次事件。
- 摁下
- 如果返回了 true 則會接收并消費該事件。
- 摁下
- 03-26 20:23:03.889 10765-10765/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent
- 如果返回 super.onTouchEvent(ev) 默認處理事件的邏輯和返回 false 時相同。
最后呢 補充一個小知識點 onTouchEvent和onClick 一般情況下 onTouchEvent 會比Onclick 執行的早 而當你在onTouchEvent 返回值為true時 是不會執行onClick方法的 但是false也沒有執行 只有默認執行了
以下 是我打的Log 大家可以看下 同時也可以發表一下建議 一起討論 true是沒有執行onclick方法 摁下 03-26 20:40:37.309 26045-26045/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:40:37.309 26045-26045/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:40:37.309 26045-26045/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:40:37.309 26045-26045/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent 抬起 03-26 20:40:37.969 26045-26045/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:40:37.969 26045-26045/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:40:37.969 26045-26045/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:40:37.969 26045-26045/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent
false 也沒有執行onClick方法 摁下 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: LinearLayout ------- > onTouchEvent 03-26 20:41:27.319 26643-26643/com.example.my_event_fenfa D/Event: Activity ------- > onTouchEvent 抬起 03-26 20:41:27.889 26643-26643/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:41:27.889 26643-26643/com.example.my_event_fenfa D/Event: Activity ------- > onTouchEvent
默認return super.onTouchEvent(event); 這里執行了onClient方法 摁下 03-26 20:43:04.919 28076-28076/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:43:04.919 28076-28076/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:43:04.919 28076-28076/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:43:04.919 28076-28076/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent 抬起 03-26 20:43:05.689 28076-28076/com.example.my_event_fenfa D/Event: Activity ------- > dispatchTouchEvent 03-26 20:43:05.689 28076-28076/com.example.my_event_fenfa D/Event: LinearLayout ------- > dispatchTouchEvent 03-26 20:43:05.689 28076-28076/com.example.my_event_fenfa D/Event: LinearLayout ------- > onInterceptTouchEvent 03-26 20:43:05.689 28076-28076/com.example.my_event_fenfa D/Event: MyView ------- > onTouchEvent 03-26 20:43:05.699 28076-28076/com.example.my_event_fenfa D/Event: View ------- > onClick
總結
- 上一篇: onkeyup和onafterpaste
- 下一篇: 毫秒时间戳转换