【Android】の基礎——View事件分發

事件分發機制

這個系列準備分享一些自己有獨特見解的知識點。

從一個故事講起

用戶點擊屏幕會觸發一個MotionEvent,它就是我們要進行分發的事件。事件分發的最終目標是希望有一個View能夠給他返回一個True,即進行了處理(消耗該事件)。在這裏,我們把事件分發的過程,比喻成一個大學生event(MotionEvent)想要在大學(Activity)中通過加入社團(ViewGroup),來尋找女盆友(View),從而找到真愛(True)的故事,我們將會以上帝視角來監視這個過程。

這裏寫圖片描述

這裏寫圖片描述
部長開會討論的怎樣分配event的過程相當於事件分發中的:
dispatchTouchEvent()

這裏寫圖片描述
如果妹紙部長不讓event進入部門裏,就是不允許事件從當前ViewGroup傳遞到子View(或者子ViewGroup),也就是攔截了event(雖然攔截但是未必處理(未必消耗)),這個過程相當於:
onInterceptTouchEvent()

這裏寫圖片描述
event找到了目標,目標可能是部長,可能是部員,也可能是其他的部門部長或者部員,這個目標可能是View,也可能是ViewGroup。反正在這個故事中,這個目標最終做出了迴應,這個過程相當於:
onTouchEvent()

所以,事件分發的核心過程我們可以用這樣一段僞代碼進行表示:

public boolean dispatchTouchEvent(MotionEvent ev){
    boolean consume = false;
    if ( onInterceptTouchEvent(ev) ){
        consume = onTouchEvent(ev);
    } else {
        consume = child.dispatchTouchEvent(ev);
    }
    return consume;
}

事件在ViewGroup中進行分發,如果沒有被消耗,則通過onInterceptTouchEvent()判斷是否需要攔截,如果攔截則交給本ViewGroup的onTouchEvent()進行處理,如果不攔截則交給子View(或ViewGroup)繼續重複dispatchTouchEvent()的過程進行分發,從外向內,以此類推。
以下:
1. 事件從Activity.dispatchTouchEvent()開始傳遞,只要沒有被停止或攔截,從最上層的View(ViewGroup)開始一直往下(子View)傳遞。子View可以通過onTouchEvent()對事件進行處理。
2. 事件由父View(ViewGroup)傳遞給子View,ViewGroup可以通過onInterceptTouchEvent()對事件做攔截,停止其往下傳遞。
3. 如果事件從上往下傳遞過程中一直沒有被停止,且最底層子View沒有消費事件,事件會反向往上傳遞,這時父View(ViewGroup)可以進行消費,如果還是沒有被消費的話,最後會到Activity的onTouchEvent()函數。
4. 如果View沒有對ACTION_DOWN進行消費,之後的其他事件不會傳遞過來。
5. OnTouchListener優先於onTouchEvent()對事件進行消費。

此外,我們在之前的故事中特別地標註了一些“重要情節”,現在來進行解釋:
這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

這裏寫圖片描述

總結下來就是:
1. 一旦 ViewGroup決定攔截,一個事件只能由他處理並且onInterceptTouchEvent不會再調用。
2. 如果View只消耗ACTION_DOWN,事件會消失(不會被parent處理),最終Activity處理。
3. View如果不消耗ACTION_DOWN,其他事件也不處理。重新交給父元素,即調用父元素onTouchEvent。
4. viewgroup默認不攔截
5. View沒有onInterceptTouchEvent
6. 除非不可點擊(clickable、longClickable都爲false),View的onTouchEvent()默認返回true,甚至enable都影響不了。
7. onTouchListener優先級高於onTouchEvent,如果onTouchListener返回True,onTouchEvent不執行

具體的源碼今後再分析。

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