我們在做一些比較絢麗的自定義控件,或者是在做一些絢麗的效果時,都離不開android的事件分發機制。所謂的事件分發機制,其實就是一個MotionEvent事件分發過程,即產生一個MotionEvent事件後,需要將MotionEvent一步一步傳遞到相應的子View,而傳遞的這個過程就是事件分發機制。
我認爲,事件分發機制分爲兩個部分,一部分爲View的事件分發機制,另一部分爲ViewGroup的事件分發機制。我會從源碼角度,帶着問題去分析事件分發機制。
1. 首先先來看看View的事件分發機制
View的事件分發主要有兩個方法
1. dispatchTouchEcent(); 用來分派事件
2. onTouchEvent ();用來處理事件
爲了方便起見,我把View的事件分發源碼整理出來,這裏只展示一部分關鍵代碼,其他的可以自行去看源碼
public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
public boolean onTouchEvent(MotionEvent event) {
switch (action) {
case MotionEvent.ACTION_UP:
performClickInternal();
break;
}
}
然後就是View事件分發流程圖
通過源碼我們可以知道
1. 當一個事件進入到當前View,首先會調用dispatchTouchEvent()方法
2. 接下來就會判斷有沒有設置onTouchListener,如果設置並返回true則不執行onTouchEvent,如果沒有設置或者設置了但返回false則執行onTouchEvent。
3. 通過源碼我們可以看到,onClickListener方法其實就是onTouchEvent中up事件中被調用總結
通過上面源碼分析,我們可以看到,在View中所有事件的執行順序是:
dispatchTouchEvent ->onTouchEventListener -> onTouchEvent -> onClickListener
現象分析
- 重寫dispatchTouchEvent、onTouchEvent、設置onTouchEventListener、設置onClickListener的執行效果。
dispatchTouchEvent.down -> onTouchEventListener.down -> onTouchEvent.down ->
dispatchTouchEvent.move -> onTouchEventListener.move -> onTouchEvent.move ->
dispatchTouchEvent.up -> onTouchEventListener.up -> onTouchEvent.up -> onClick
這個效果符合源碼分析中2中onTouchListener返回false時執行onTouchEvent
- 重寫dispatchTouchEvent、onTouchEvent、設置onTouchEventListener、設置onClickListener但是onTouchEventListener返回true的執行效果。
dispatchTouchEvent.down -> onTouchEventListener.down ->
dispatchTouchEvent.move -> onTouchEventListener.move ->
dispatchTouchEvent.up -> onTouchEventListener.up
這個效果符合源碼分析中2中onTouchListener返回true時不執行onTouchEvent
- 重寫dispatchTouchEvent、onTouchEvent、設置onTouchEventListener、設置onClickListener但是dispatchTouchEvent返回值不是super而是true的執行效果
dispatchTouchEvent.down -> onTouchEventListener.move -> dispatchTouchEvent.up
這個效果出現的原因,是因爲當我們重寫dispatchTouchEvent沒有返回super,那麼我們就不會調用View的dispatchTouchEvent所以他沒有走onTouchEventListener以下的事件,同理onTouchEvent返回true也是一樣的原因。
思考
不知道大家有沒有發現我有幾個效果在這裏沒有分析
- 重寫dispatchTouchEvent、onTouchEvent、設置onTouchEventListener、設置onClickListener但是dispatchTouchEvent返回值不是super而是false的執行效果
- 重寫dispatchTouchEvent、onTouchEvent、設置onTouchEventListener、但是不設置onClickListener的執行效果。
至於爲什麼沒有分析,是因爲上面兩個效果,會涉及到ViewGroup的事件分發,想要知道上面兩種會出現什麼效果,以及出現這種效果的原因請移步ViewGroup的事件分發機制,同時View的事件分發機制就到這裏了。