點擊事件傳遞規律

點擊事件的分發過程有三個主要的方法:

onTouchEvent:

onTouchEvent是在view中定義的一個方法。處理傳遞到view 的手勢事件。手勢事件類型包括ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL四種事件。一旦onTouchEvent方法被調用,並返回true則這個手勢事件就結束了,並不會繼續傳遞到子控件。

onInterceptTouchEvent:

onInterceptTouchEvent是在ViewGroup裏面定義的。Android中的ViewGroup佈局類都會繼承此類的。onInterceptTouchEvent是用於攔截手勢事件的,每個手勢事件都會先調用onInterceptTouchEvent。

onInterceptTouchEvent()用於處理事件並改變事件的傳遞方向。返回值爲false時事件會傳遞給子控件的onInterceptTouchEvent();返回值爲true時事件會傳遞給當前控件的onTouchEvent(),而不在傳遞給子控件。由於onInterceptTouchEvent()的機制比較複雜,有一下幾種:

1.down事件首先會傳遞到onInterceptTouchEvent()方法
2.如果該ViewGroup的onInterceptTouchEvent()在接收到down事件處理完成之後return false,那麼後續的move,up等事件將繼續會先傳遞給該ViewGroup,之後才和down事件一樣傳遞給最終的目標view的onTouchEvent()處理。
3.如果該ViewGroup的onInterceptTouchEvent()在接收到down事件處理完成之後return true,那麼後續的move,up等事件將不再傳遞給onInterceptTouchEvent(),而是和down事件一樣傳遞給該ViewGroup的onTouchEvent()處理,注意,目標view將接收不到任何事件。
4.如果最終需要處理事件的view的onTouchEvent()返回了false,那麼該事件將被傳遞至其上一層次的view的onTouchEvent()處理。
5.如果最終需要處理事件的view 的onTouchEvent()返回了true,那麼後續事件將可以繼續傳遞給該view的onTouchEvent()處理。

dispatchTouchEvent

該方法用來進行事件的分發,即無論ViewGroup或者View的事件,都是從這個方法開始的。然後就會執行上面的操作,直到這個事件被消耗。通過源代碼的分析,大體是這樣的:如果一個事件傳遞到了ViewGroup處,首先會判斷當前ViewGroup是否要攔截事件,即調用onInterceptTouchEvent()方法;如果返回true,則表示ViewGroup攔截事件,那麼ViewGroup就會調用自身的onTouchEvent來處理事件;如果返回false,表示ViewGroup不攔截事件,此時事件會分發到它的子View處,即調用子View的dispatchTouchEvent方法,如此反覆直到事件被消耗掉。


傳遞機制一些結論

【Android開發藝術探索內容整理】
(1)OnTouchListener的優先級比onTouchEvent要高
如果給一個view設置了OnTouchListener,那麼OnTouchListener中的onTouch方法會被回調。這時事件如何處理還要看onTouch的返回值,如果返回false,那麼OnTouchListener中的onTouch方法不會被回調,就輪到當前view的onTouchEvent方法會被調用;如果返回true,那麼onTouchEvent方法將不會被調用。
在onTouchEvent方法中,如果當前view設置了OnClickListener,那麼它的onClick方法會被調用,由此可見我們平時常用的OnClickListener的優先級最低,處於事件傳遞的尾端。
(2)當一個點擊事件發生之後,傳遞過程遵循如下順序:Activity -> Window -> View。
如果一個view的onTouchEvent方法返回false,那麼它的父容器的onTouchEvent方法將會被調用,依此類推,如果所有的元素都不處理這個事件,那麼這個事件將會最終傳遞給Activity處理(調用Activity的onTouchEvent方法)。
(3)同一個事件序列是指觸摸屏幕的那一刻起,到手指離開屏幕的那一刻結束,在這個過程中所產生的一系列事件,這個事件徐柳以down事件開始,中間含有數量不定的move事件,最終以up事件結束。
(4)正常情況下,一個事件序列只能被一個View蘭家且消耗,原因參考5),因爲一旦一個元素攔截了某些事件,那麼同一個事件序列的所有事件都會交給它處理,但不是絕對的,可以強制。
(5)某個View一旦決定攔截,那麼這個一個事件序列都只能由它來處理,並且它的onInterceptTouchEvent方法不會被再次調用。
(6)某個View一旦開始處理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false),那麼這個一個事件序列都不會交給它來處理,並且事件將重新交給它的父容器去處理。
(7)如果它消耗ACTION_DOWN事件,但是不消耗其他類型事件,那麼這個點擊事件會消失,父容器的onTouchEvent方法不會被調用,當前view依然可以收到後續的事件,但是這些事件最後都會傳遞給Activity處理。
(8)如果所有的View都不處理事件,這個事件最終會消失。
(9)ViewGroup默認不攔截任何事件,因爲它的onInterceptTouchEvent方法默認返回false。
(10)View沒有onInterceptTouchEvent方法,也就是不攔截事件,只要有時間傳遞給它,它的onTouchEvent方法就會被調用。
(11)View的onTouchEvent默認都會消耗事件,也就是onTouchEvent方法返回true。除非它是不可點擊的(clickable和longclickable同時爲false)。View的longclickable默認爲false,clickable要看情況,比如Button默認是true,也就是Button默認會消耗事件,onTouchEvent方法返回true。
(12)View的enable屬性不影響onTouchEvent的默認返回值。哪怕一個view是disable狀態,只要它的clickable或者longClickable有一個是true,那麼它的onTouchEvent就會返回true。
(13)onClick會發生的前提是當前View是可點擊的,並且它收到了down和up事件。
(14)事件傳遞過程是由外向內的,即事件總是先傳遞給父元素,然後再由父元素傳遞給子View,但是子元素可以通過requestDisallowTouchEvent方法干擾父元素的分發過程,但是down事件除外。

發佈了46 篇原創文章 · 獲贊 23 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章