Android事件傳遞機制解析

在Android開發中咱們可能會遇到這樣的問題,onTouch與onTouchEvent的區別是什麼?onTouch與onClick又有什麼區別?何時須要重寫onTouchEvent事件進行使用呢?爲何我寫的view沒有不論點擊仍是滑動都沒響應呢?等等這一系列的問題都與Android的事件分發機制有關,如今咱們來慢慢剖析Android的事件分發原理。html

先提倆個問題:

  1. 事件是怎麼傳遞的?
  2. 事件又是如何處理?

Android中與事件有關的API函數是:git

public boolean dispatchTouchEvent(MotionEvent ev); //分發事件
public boolean onInterceptTouchEvent(MotionEvent ev); //攔截事件
public boolean onTouchEvent(MotionEvent ev); //處理事件github

1、事件分發機制

一、事件是如何傳遞的:

ViewGroup接收到事件後進行事件的分派,若是本身須要處理這個事件,則進行攔截;若是不處理,則傳遞給子View進行處理,而後由子view進行分派,攔截和處理。可類比於:上級接到任務後進行任務分派,若是上級本身處理這個任務,則本身處理;若是不想處理,則把這個任務丟給下級進行處理...函數

咱們須要注意:ui

viewGroup中包含的最小子view是不含攔截onInterceptTouchEvent事件的,最小的子view好比Button,TextView...由於他們已在樹的最低層,已沒法向下傳遞了。spa

上圖左邊部分很清楚形象的描述了事件的傳遞:.net

  • 對於ViewGroup,接收事件後,進行分發:code

    • 若是不進行分發,則dispatchTouchEv返回true,事件消亡未處理。
    • 若是進行分發該事件,則dispatchTouchEvent返回false,處理或傳遞該事件:orm

      • 若是想本身處理該事件,則onInterceptTouchEvent返回true,攔截事件,給本身的onTouchEvent進行處理;
      • 若是不想處理該事件,則onInterceptTouchEvent返回false,把事件傳遞給子View進行處理。
  • 對於最底層的子View,沒有onInterceptEvent攔截事件,接收到事件後進行分發:htm

    • 若是不進行分發,則dispatchTouchEvent返回false,事件未處理,注意這裏的最小子view返回false表明未分發事件;
    • 若是進行分發該事件,則dispatchTouchEvent返回true:

      • 若是處理該事件,則onTouchEvent返回true把該事件消費掉;
      • 若是不想處理該事件,則onTouchEvent返回false,等待上級處理。

上邊所講的是ViewGroup與最底層的子view之間的事件傳遞,那Android整個事件的傳遞機制該如何呢?

首先由Activity分發事件(和最底層的子View同樣無攔截事件,由於最頂層嘛,攔截了就沒法傳遞了),先分發給根View,也就是DecorViewDeCorView爲整個Window界面的最頂層的View,包含通知欄,標題欄,內容顯示欄三塊區域,咱們常常寫的setContentView就是爲DecorView中的內容欄進行設置),而後由根View分發到子View。

二、事件是如何處理的:

倘若通過分發與攔截後,最終將事件傳遞到了某個子View,則事件處理以下圖所示:

子View的onTouchEvent進行事件處理,若是返回true,則消耗此事件,不會再繼續傳遞;若是返回false,則不處理此事件,把這個事件往上一級的ViewGroup進行傳遞,由上一級進行處理可類好比:上級把任務交給你進行處理,但因爲能力不夠沒法處理,則把任務交給上一級進行處理,若是上一級還處理不了,則繼續往上傳遞處理。最終事件是否處理,由子View和ViewGroup的onTouchEvent的返回值決定是否會把事件消耗掉。

2、onTouch事件

一、onTouch與onTouchEvent

想弄清楚這倆個的關係,咱們能夠先來看一下他們在源碼中的位置:

  • 首先咱們要清楚,dispatchTouchEvent是onTouchEvent,onTouch和onInterceptEvent的入口,他們都是在dispatchTouchEvent分發事件中決定是否要攔截和處理的;
  • 其次,黃線表明onTouch事件的位置,紅線表明onTouchEvent事件的位置,能夠獲得,onTouch的執行順序老是在onTouchEvent事件前的;並且若是onTouch執行後返回true後,就會使得result爲true,不會再去執行onTouchEvent事件了,只有當onTouch事件沒有執行或返回爲false時onTouchEvent纔會獲得執行。
  • onTouch執行須要倆個前提條件:其一是須要設置mOnTouchListener,其二是當前View必需要enable。若是控件爲disable,則onTouch事件無論怎麼樣都不會執行;但若是須要響應觸摸事件呢?這時咱們不是還有onTouchEvent事件嘛,重寫一下onTouchEvent方法來實現Touch的響應就好了。

二、onTouch與onClick

查看源碼,咱們發現:

onClick事件藏在onTouchEvent事件的ACTION_UP中,也就是標示的performClick,這樣結合上面onTouch與onTouchEvent事件的關係,能夠很容易獲得:

  • 執行前後不同。觸摸事件先執行(onTouch>onClick)
  • 觸摸事件返回值影響點擊事件(前者影響後者,然後者不影響前者);onTouch方法的返回值改成true時,只執行onTouch事件,不執行onClick事件,固然也不執行onTouchEvent事件。

參考資料:

本文發表於我的博客:http://lavnfan.github.io/,歡迎指教。

相關文章
相關標籤/搜索