掃盲細節,Android 的事件分發機制

事件都是從用戶按下(ACTION_DOWN)的那一刻產生的,三個非常重要的與事件相關的方法:

  • dispatchTouchEvent()
  • onTouchEvent()
  • onInterceptTouchEvent()

Activity 的事件分發機制

從單詞含義已經很明顯的知道,dispatchTouchEvent() 是負責事件分發的。當點擊事件產生後,事件首先會傳遞給當前的 Activity,這會調用 Activity 的 dispatchTouchEvent() 方法,看看源碼中是怎麼處理的。

由於我們一般產生點擊事件都是 MotionEvent.ACTION_DOWN,所以一般都會調用到 onUserInteraction() 這個方法。

很遺憾,這個方法實現是空的,不過可以從註釋和其他途徑可以瞭解到,該方法主要的作用是實現屏保功能,並且當此 Activity 在棧頂的時候,觸屏點擊 Home、Back等都會觸發這個方法。

再來看看第二個 if 語句,getWindow().superDispatchTouchEvent()getWindow() 明顯是獲取 Window,由於 Window 是一個抽象類,所以我們能拿到其子類 PhoneWindow,直接看看 PhoneWindows.superDispatchTouchEvent() 到底做了什麼操作。

直接調用了 DecorView 的 superDispatchTrackballEvent() 方法。DecorView 繼承於 FrameLayout,而 FrameLayout 作爲 ViewGroup 的子類,所以直接調用了 ViewGroup 的 dispatchTouchEvent()

ViewGroup 的事件分發機制

查看 ViewGroup 的 dispatchTouchEvent() :

注意其中紅框裏面的代碼,看註釋也能知道,定義了一個 boolean 值變量 intercept 來表示是否要攔截事件。

其中採用到了 onInterceptTouchEvent(ev) 對 intercept 進行賦值。大多數情況下,onInterceptTouchEvent() 返回值爲 false,但我們完全可以通過重寫 onInterceptTouchEvent(ev) 來改變它的返回值,繼續往下看後面對這個 intercept 做了什麼處理。

暫時忽略 判斷的 canceled,該值同樣大多數時候都返回 false,所以當我們沒有重寫 onInterceptTouchEvent() 並使它的返回值爲 true 時,一般情況下都是可以進入到該方法的。

繼續閱讀源碼可以發現,裏面做了一個 for 循環,通過倒序遍歷 ViewGroup 下面的所有子 View,然後一個一個判斷點擊位置是否是該子 View 的佈局區域,當然還有一些其他的,由於篇幅原因,這裏就不細講了。

View 的事件分發機制

ViewGroup 說到底還是一個 View,所以我們不得不繼續看看 View 的 dispatchTouchEvent()

  • (mViewFlags & ENABLED_MASK) == ENABLED
    判斷當前點擊的控件是否爲 enable,但由於基本 View 都是 enable 的,所以這個條件基本都返回 true。

  • mOnTouchListener.onTouch(this, event)
    即我們調用 setOnTouchListener() 時必須覆蓋的方法 onTouch() 的返回值。

從上述的分析,終於知道「onTouch() 方法優先級高於 onTouchEvent(event) 方法」是怎麼來的了!!

再看 onTouchEvent()

從上面的代碼可以明顯地看到,只要 View 的 CLICKABLE 和 LONG_CLICKABLE 有一個爲 true,那麼 onTouchEvent() 就會返回 true 消耗這個事件。CLICKABLE 和 LONG_CLICKABLE 代表 View 可以被點擊和長按點擊,我們通常都會採用 setOnClickListener() 和 setOnLongClickListener() 做設置。接着在 ACTION_UP 事件中會調用 performClick() 方法。

從截圖中可以看到,如果 mOnClickListener 不爲空,那麼它的 onClick() 方法就會調用。

總結

  • Activity 的事件分發示意圖

  • ViewGroup 事件分發示意圖

  • View 的事件分發示意圖

  • 事件分發工作流程總結

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章