在Android開發中咱們可能會遇到這樣的問題,onTouch與onTouchEvent的區別是什麼?onTouch與onClick又有什麼區別?何時須要重寫onTouchEvent事件進行使用呢?爲何我寫的view沒有不論點擊仍是滑動都沒響應呢?等等這一系列的問題都與Android的事件分發機制有關,如今咱們來慢慢剖析Android的事件分發原理。html
Android中與事件有關的API函數是:git
public boolean dispatchTouchEvent(MotionEvent ev); //分發事件
public boolean onInterceptTouchEvent(MotionEvent ev); //攔截事件
public boolean onTouchEvent(MotionEvent ev); //處理事件
github
ViewGroup接收到事件後進行事件的分派,若是本身須要處理這個事件,則進行攔截;若是不處理,則傳遞給子View進行處理,而後由子view進行分派,攔截和處理。可類比於:上級接到任務後進行任務分派,若是上級本身處理這個任務,則本身處理;若是不想處理,則把這個任務丟給下級進行處理...函數
咱們須要注意:ui
viewGroup中包含的最小子view是不含攔截onInterceptTouchEvent事件的,最小的子view好比Button,TextView...由於他們已在樹的最低層,已沒法向下傳遞了。spa
上圖左邊部分很清楚形象的描述了事件的傳遞:.net
對於ViewGroup,接收事件後,進行分發:code
若是進行分發該事件,則dispatchTouchEvent返回false,處理或傳遞該事件:orm
對於最底層的子View,沒有onInterceptEvent攔截事件,接收到事件後進行分發:htm
若是進行分發該事件,則dispatchTouchEvent返回true:
上邊所講的是ViewGroup與最底層的子view之間的事件傳遞,那Android整個事件的傳遞機制該如何呢?
首先由Activity分發事件(和最底層的子View同樣無攔截事件,由於最頂層嘛,攔截了就沒法傳遞了),先分發給根View,也就是DecorView(DeCorView爲整個Window界面的最頂層的View,包含通知欄,標題欄,內容顯示欄三塊區域,咱們常常寫的setContentView就是爲DecorView中的內容欄進行設置),而後由根View分發到子View。
倘若通過分發與攔截後,最終將事件傳遞到了某個子View,則事件處理以下圖所示:
子View的onTouchEvent進行事件處理,若是返回true,則消耗此事件,不會再繼續傳遞;若是返回false,則不處理此事件,把這個事件往上一級的ViewGroup進行傳遞,由上一級進行處理。可類好比:上級把任務交給你進行處理,但因爲能力不夠沒法處理,則把任務交給上一級進行處理,若是上一級還處理不了,則繼續往上傳遞處理。最終事件是否處理,由子View和ViewGroup的onTouchEvent的返回值決定是否會把事件消耗掉。
想弄清楚這倆個的關係,咱們能夠先來看一下他們在源碼中的位置:
查看源碼,咱們發現:
onClick事件藏在onTouchEvent事件的ACTION_UP中,也就是標示的performClick,這樣結合上面onTouch與onTouchEvent事件的關係,能夠很容易獲得:
參考資料:
本文發表於我的博客:http://lavnfan.github.io/,歡迎指教。