Android事件分發機制

前言

在安卓四大組件中(ActivityServiceBroadCastContentProvider),最經常使用的當是Activity。由於Activity負責提供直觀的頁面並響應用戶操做。在Activity的佈局文件中,經過最外層的ViewGroup(佈局)一層層嵌套、佈局直至View(控件),組成了豐富多彩的用戶頁面。如QQ、微信等等。在開發這些頁面過程當中,不免會遇到一些事件衝突(說人話就是:你想點擊的某個佈局或控件,發現響應的是另外一個佈局或控件)的問題。呵呵,怎麼辦呢?由此引入咱們接下來討論的問題。git

事件分發闡述

手機在響應用戶的點擊操做時,從Activity入口,遵循着必定的規則將對應的事件交由指定的ViewGroup或者View去響應(消費這個事件)。只有找出了各中規則,往後再次處理這類事件問題時,一定會駕輕就熟。從程序的角度來看,Android提供三個方法處理事件問題dispatchTouchEvent分發點擊事件)、onInterceptTouchEvent攔截點擊事件),onTouchEvent處理點擊事件)。每一個方法返回truefalse表示是否處理它對應的職責。好比說,若是我攔截了事件,就表示自身要處理該事件,不讓別的控件再能接收到事件信號。除了返回truefalse以外,還能經過調用父類的方法執行父類的邏輯。簡而言之,ActivityViewGroupView三個類處理事件,相關的方法依次是dispatchTouchEventonInterceptTouchEventonTouchEvent以及每一個方法的返回能夠是truefalsesuper。其中注意:ActivityView沒有攔截事件方法。github

驗證

編寫一個測試demo,佈局文件中用LinearLayout嵌套RelativeLayout,最後在RelativeLayout中包含一個Button按鈕。依次在每一個事件處理方法中,輸出log日誌。點擊按鈕測試,經過日誌信息分析事件分發流程。下圖是佈局效果。微信

爲方便描述,定製命名規則:Activity簡寫ALinearLayout簡寫LRelativeLayout簡寫RButton簡寫BdispatchTouchEvent簡寫DonInterceptTouchEvent簡寫IonTouchEvent簡寫T,返回true簡寫T,返回false簡寫F,返回super簡寫S。如:ADS表示ActivitydispatchTouchEvent方法 return superide

測試方案一

ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTS、BDS/BTS
複製代碼

日誌說明佈局

04-01 12:44:44.402: D/Activity(1234): dispatchTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyLinearLayout(1234): dispatchTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyLinearLayout(1234): onInterceptTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyRelativeLayout(1234): dispatchTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyRelativeLayout(1234): onInterceptTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyButton(1234): dispatchTouchEvent ACTION_DOWN
04-01 12:44:44.402: D/MyButton(1234): onTouchEvent ACTION_DOWN
04-01 12:44:44.506: D/Activity(1234): dispatchTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyLinearLayout(1234): dispatchTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyLinearLayout(1234): onInterceptTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyRelativeLayout(1234): dispatchTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyRelativeLayout(1234): onInterceptTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyButton(1234): dispatchTouchEvent ACTION_UP
04-01 12:44:44.506: D/MyButton(1234): onTouchEvent ACTION_UP
04-01 12:44:44.506: D/Button(1234): 點擊
複製代碼

整理出以下示意圖:三色箭頭實線,表示對應方法返回一個值會跳轉到下一個方法。其中Button 返回true和返回super都會消費事件,只是返回true就不在就再也不響應button的點擊事件。測試

測試方案二

ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTS、BDS/BTF
複製代碼

日誌說明spa

04-01 14:00:54.970: D/Activity(1387): dispatchTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyLinearLayout(1387): dispatchTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyLinearLayout(1387): onInterceptTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyRelativeLayout(1387): dispatchTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyRelativeLayout(1387): onInterceptTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyButton(1387): dispatchTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyButton(1387): onTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyRelativeLayout(1387): onTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/MyLinearLayout(1387): onTouchEvent ACTION_DOWN
04-01 14:00:54.970: D/Activity(1387): onTouchEvent ACTION_DOWN
04-01 14:00:55.066: D/Activity(1387): dispatchTouchEvent ACTION_UP
04-01 14:00:55.066: D/Activity(1387): onTouchEvent ACTION_UP
複製代碼

說明:Button 的onTouchEvent return false時,點擊事件會返回到上一層視圖。若是一直都沒有控件處理這個事件就會交給Activitiy 的onTouchEvent消費。當再傳入事件時,不會再按照以前的流程,每一個空間均處理一次,而是直接給 Activity 的onTouchEvent消費。就是虛線所指。3d

測試方案三

ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTS、BDT/BTF
複製代碼

日誌說明日誌

04-01 14:12:47.918: D/Activity(1444): dispatchTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyLinearLayout(1444): dispatchTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyLinearLayout(1444): onInterceptTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyRelativeLayout(1444): dispatchTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyRelativeLayout(1444): onInterceptTouchEvent ACTION_DOWN
04-01 14:12:47.918: D/MyButton(1444): dispatchTouchEvent ACTION_DOWN
04-01 14:12:48.030: D/Activity(1444): dispatchTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyLinearLayout(1444): dispatchTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyLinearLayout(1444): onInterceptTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyRelativeLayout(1444): dispatchTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyRelativeLayout(1444): onInterceptTouchEvent ACTION_UP
04-01 14:12:48.030: D/MyButton(1444): dispatchTouchEvent ACTION_UP
複製代碼

說明:Button dispatchTouchEvent方法返回true,表示自身須要消費該事件。且不傳遞給onTouchEvent方法。code

測試方案四

ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTS、BDF/BTF
複製代碼

日誌說明

04-01 14:19:40.014: D/Activity(1502): dispatchTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyLinearLayout(1502): dispatchTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyLinearLayout(1502): onInterceptTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyRelativeLayout(1502): dispatchTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyRelativeLayout(1502): onInterceptTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyButton(1502): dispatchTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyRelativeLayout(1502): onTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/MyLinearLayout(1502): onTouchEvent ACTION_DOWN
04-01 14:19:40.014: D/Activity(1502): onTouchEvent ACTION_DOWN
04-01 14:19:40.022: D/Activity(1502): dispatchTouchEvent ACTION_UP
04-01 14:19:40.022: D/Activity(1502): onTouchEvent ACTION_UP
複製代碼

說明:Button dispatchTouchEvent方法返回false,事件傳遞給父控件onTouchEvent方法。

測試方案五

ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTT、BDF/BTF
複製代碼

日誌說明

04-01 14:26:03.306: D/Activity(1561): dispatchTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyLinearLayout(1561): dispatchTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyLinearLayout(1561): onInterceptTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyRelativeLayout(1561): dispatchTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyRelativeLayout(1561): onInterceptTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyButton(1561): dispatchTouchEvent ACTION_DOWN
04-01 14:26:03.306: D/MyRelativeLayout(1561): onTouchEvent ACTION_DOWN
04-01 14:26:03.366: D/Activity(1561): dispatchTouchEvent ACTION_UP
04-01 14:26:03.366: D/MyLinearLayout(1561): dispatchTouchEvent ACTION_UP
04-01 14:26:03.366: D/MyLinearLayout(1561): onInterceptTouchEvent ACTION_UP
04-01 14:26:03.366: D/MyRelativeLayout(1561): dispatchTouchEvent ACTION_UP
04-01 14:26:03.366: D/MyRelativeLayout(1561): onTouchEvent ACTION_UP
複製代碼

說明:RelativeLayout 的onTouchEvent方法return true 消費了事件,下次事件生成時,就不傳遞給Button,直接交由RelativeLayout 的onTouchEvent方法處理。

測試方案六

ADS/ATS、LDS/LIS/LTS、RDS/RIS/RTF、BDF/BTF
複製代碼

日誌說明

04-01 14:39:20.794: D/Activity(1644): dispatchTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyLinearLayout(1644): dispatchTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyLinearLayout(1644): onInterceptTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyRelativeLayout(1644): dispatchTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyRelativeLayout(1644): onInterceptTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyButton(1644): dispatchTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyRelativeLayout(1644): onTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/MyLinearLayout(1644): onTouchEvent ACTION_DOWN
04-01 14:39:20.798: D/Activity(1644): onTouchEvent ACTION_DOWN
04-01 14:39:20.874: D/Activity(1644): dispatchTouchEvent ACTION_UP
04-01 14:39:20.874: D/Activity(1644): onTouchEvent ACTION_UP
複製代碼

說明:RelativeLayout return false,就會將事件傳遞到上一層控件消費。其中,RelativeLayout onInterceptTouchEvent return false 表示事件也會分發到Button處理。

測試方案七

ADS/ATS、LDS/LIS/LTS、RDS/RIT/RTF、BDF/BTF
複製代碼

日誌說明

04-01 15:02:41.594: D/Activity(1739): dispatchTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyLinearLayout(1739): dispatchTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyLinearLayout(1739): onInterceptTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyRelativeLayout(1739): dispatchTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyRelativeLayout(1739): onInterceptTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyRelativeLayout(1739): onTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/MyLinearLayout(1739): onTouchEvent ACTION_DOWN
04-01 15:02:41.594: D/Activity(1739): onTouchEvent ACTION_DOWN
04-01 15:02:41.714: D/Activity(1739): dispatchTouchEvent ACTION_UP
04-01 15:02:41.714: D/Activity(1739): onTouchEvent ACTION_UP
複製代碼

說明:RelativeLayout onInterceptTouchEvent 返回true,表示RelativeLayout 攔截事件信息,Button不會響應事件,事件交由RelativeLayout onTouchEvent處理。

測試方案八

ADS/ATS、LDS/LIS/LTS、RDT/RIT/RTF、BDF/BTF
複製代碼

日誌說明

04-01 15:27:17.002: D/Activity(1907): dispatchTouchEvent ACTION_DOWN
04-01 15:27:17.002: D/MyLinearLayout(1907): dispatchTouchEvent ACTION_DOWN
04-01 15:27:17.002: D/MyLinearLayout(1907): onInterceptTouchEvent ACTION_DOWN
04-01 15:27:17.002: D/MyRelativeLayout(1907): dispatchTouchEvent ACTION_DOWN
04-01 15:27:17.058: D/Activity(1907): dispatchTouchEvent ACTION_UP
04-01 15:27:17.058: D/MyLinearLayout(1907): dispatchTouchEvent ACTION_UP
04-01 15:27:17.058: D/MyLinearLayout(1907): onInterceptTouchEvent ACTION_UP
04-01 15:27:17.058: D/MyRelativeLayout(1907): dispatchTouchEvent ACTION_UP
複製代碼

說明:RelativeLayout dispatchTouchEvent return true 表示本身消費事件,再也不進行傳遞

測試方案九

ADS/ATS、LDS/LIS/LTS、RDF/RIT/RTF、BDF/BTF
複製代碼

日誌說明

04-01 15:32:12.138: D/Activity(1965): dispatchTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/MyLinearLayout(1965): dispatchTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/MyLinearLayout(1965): onInterceptTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/MyRelativeLayout(1965): dispatchTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/MyLinearLayout(1965): onTouchEvent ACTION_DOWN
04-01 15:32:12.138: D/Activity(1965): onTouchEvent ACTION_DOWN
04-01 15:32:12.250: D/Activity(1965): dispatchTouchEvent ACTION_UP
04-01 15:32:12.250: D/Activity(1965): onTouchEvent ACTION_UP
複製代碼

說明:RelativeLayout dispatchTouchEvent return false 表示不處理事件,交給上層頁面處理。

測試方案十

ADT/ATS、LDS/LIS/LTS、RDF/RIT/RTF、BDF/BTF
複製代碼

日誌說明

04-01 15:43:24.558: D/Activity(2023): dispatchTouchEvent ACTION_DOWN
04-01 15:43:24.686: D/Activity(2023): dispatchTouchEvent ACTION_UP
複製代碼

說明:同ViewGroup和View的 dispatchTouchEvent 方法同樣,return true 表示本身消費事件。不一樣的是,Activity 的dispatchTouchEvent方法return false 也表示本身消費事件。

測試方案十一

ADS/ATS、LDS/LIS/LTS、RDF/RIT/RTF、BDF/BTF
複製代碼

日誌說明

04-01 15:56:51.486: D/Activity(2149): dispatchTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/MyLinearLayout(2149): dispatchTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/MyLinearLayout(2149): onInterceptTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/MyRelativeLayout(2149): dispatchTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/MyLinearLayout(2149): onTouchEvent ACTION_DOWN
04-01 15:56:51.486: D/Activity(2149): onTouchEvent ACTION_DOWN
04-01 15:56:51.490: D/Activity(2149): dispatchTouchEvent ACTION_UP
04-01 15:56:51.490: D/Activity(2149): onTouchEvent ACTION_UP
複製代碼

說明:其實,最終只要傳遞到Activity的onTouchEvent 方法,都會交由它處理事件。

參照以前理解的思路,將整個示意圖完善以下:

總結

  1. ActivitydispatchTouchEvent方法,執行父類dispatchTouchEvent方法時,會將事件分發至ViewGroup,不然自身消費事件。
  2. 當事件再次傳遞到ActivityonTouchEvent方法,表示頁面中全部控件都不響應事件,由Activity處理。
  3. ViewGroupViewdispatchTouchEvent方法,return true表示不分發事件,自身處理。return false就將事件傳遞給上層控件的onTouchEvent方法,而且再也不響應上層控件傳遞過來的事件。
  4. ViewGrouponInterceptTouchEvent方法return true表示攔截事件,將事件傳遞給自身的onTouchEvent方法處理。
  5. ViewonTouchEvent方法return false表示不消費事件,將事件傳遞給上層控件的onTouchEvent方法。不然,消費事件。
  6. ViewGrouponTouchEvent方法return true表示消費事件,不然將事件傳遞給上層控件或ActivityonTouchEvent方法處理。
  7. 當控件沒有處理事件時,就再也不接收下一個事件消息,虛線所示。

最近在構建本身的博客主頁,正在將以前的博客遷移過去。有興趣請點擊Flueky Tech-site

相關文章
相關標籤/搜索