前言
在我們的專案中,遇到比較複雜佈局的時候,最常見的就是佈局巢狀和自定義控制元件,那麼滑動衝突與點選衝突你一定是遇到過的,解決的方法有很多,但是總的來說都是對onTouch事件傳遞做處理.那麼我們就來了解一下onTouch事件到底是怎麼傳遞的
1.基本知識
我們先看看相關的幾個方法
(View是沒有onInterceptTouchEvent方法的)
ViewGroup
- 1. dispatchTouchEvent(分發touch事件)
- 2. onInterceptTouchEvent(攔截touch事件)
- 3. onTouchEvent(消費事件)
View
- 1. dispatchTouchEvent(分發touch事件)
- 2. onTouchEvent(消費事件)
一個事件首先會由dispatchTouchEvent決定怎麼分配,接著由onInterceptTouchEvent決定是否攔截,最後由onTouchEvent決定怎麼消費
一般來說我們會重寫onInterceptTouchEvent和onTouchEvent方法來改變事件的傳遞,但是不會去重寫dispatchTouchEvent方法
下面為了更好的描述,有些地方就用簡稱描述了
- dispatchTouchEvent : 分配
- onInterceptTouchEvent : 攔截
2. 傳遞規律
(1)基本傳遞方向
首先我們需要知道onTouch事件傳遞的基本傳遞方向,onTouch事件的傳遞方向大概是從父控制元件傳遞到子控制元件,然後再從子控制元件傳回父控制元件,這個過程中一旦事件被消費了,那麼事件就不會繼續傳遞了
(2)攔截
onInterceptTouchEvent方法會有一個返回值,如果你返回的是false,表示不攔截,那麼事件就會先往子控制元件傳遞,如果你返回的是true,表示攔截,那麼事件不會往下傳遞了
(3)消費
可以消費事件的地方有兩個:
- OnTouchListener: 通過setOnTouchListener設定的OnTouchListener裡面的onTouch方法
- onTouchEvent: 控制元件本身的onTouchEvent方法
這兩個方法都有返回值,如果你返回的是true,代表事件被消費了,如果你返回的是false,那麼就算你在方法裡做了很多事,也不算消費
當OnTouchListener存在的時候,會先獲取到事件,如果不消費的話才會傳到onTouchEvent
OnTouchListener雖然優先於onTouchEvent,但都屬於同一層的消費,在這裡我們就不分開來描述了,統一描述為自己消費
(OnTouchListener > onTouchEvent)
(4)一組事件
move和up事件往往是和dowm事件相關聯的,為了簡化描述,我們這裡就把down,move,up同一稱為一組事件(下一次down事件之後的算下一組)
(5)控制元件
這裡指的所有控制元件都是在onTouch事件的點選範圍內,如果不在這個點選範圍內的控制元件,是不會參與事件傳遞的
3.傳遞路線
一個控制元件獲取到事件時,首先會走dispatchTouchEvent,才會走onInterceptTouchEvent和onTouchEvent,一般我們都不會去重寫dispatchTouchEvent方法(研究原始碼的需要重點研究這個方法),所以接下來的傳遞路線就跳過dispatchTouchEvent這個方法了
這個例子裡面只有一個ViewGroup,ViewGroup裡面有隻有一個View
4.要點
(1)攔截
①如果ViewGroup在onInterceptTouchEvent裡面攔截了down事件,那麼這一組事件都不會再進入onInterceptTouchEvent方法裡面了,也不會分配到View裡面了
(2)消費
①如果ViewGroup消費了down事件,那麼這一組事件不會進入到onInterceptTouchEvent裡面了,更不會分配到View裡面了,而是直接從dispatchTouchEvent方法走到自己消費的方法裡
(3)多個View
如果ViewGroup有多個View,那麼會從最上面的view遍歷,如果有view消費了down事件,那麼就不會繼續遍歷了,而且這一組事件也會直接進入這個view
(還會走ViewGroup的分配和攔截方法)
5.總結
onTouch事件的傳遞有很多可能的路線,這裡就不貼出筆者當初研究的DEMO程式碼了,免得看得頭暈.你只要知道幾個主要的原則和規律,再複雜的情況你也能夠知道事件會怎麼傳遞,這裡就再次總結一下
(1)一個ViewGroup有三種方法,分配,攔截,消費
- 分配: dispatchTouchEvent
- 攔截: onInterceptTouchEvent
- 消費: OnTouchListener和onTouchEvent (優先走OnTouchListener的onTouch)
(View的話沒有攔截)
(2)首先事件會從父控制元件開始,逐級往下傳遞
(2)事件經過某個控制元件的時候,會先走分配,再走攔截,如果不攔截又會接著往下分配
(3)事件從上往下分配時,要麼是走到某一層被攔截了,要麼是走到最底層了才會停止向下分配
(4)一旦停止向下傳遞,就要開始考慮消費的事了
(5)從停止傳遞的那一層開始,詢問是否要消費事件,如果自己不消費,那麼逐級往上詢問
(6)一旦某層把事件消費了,那麼就不再向上詢問,事件傳遞就到此結束了
6.思維導圖
筆者當初第一次研究的時候做了一個DEMO,並把傳遞的過程用思維導圖詳細的記錄了下來,有興趣的朋友可以去下載看看,免費的哦,不過還是建議有時間的朋友能夠自己寫demo測試一下,這樣才能更好的理解.
download.csdn.net/download/yu…