Android中ViewGroup的事件分發結論記錄
阿新 • • 發佈:2019-03-10
這裡記錄一下關於ViewGroup中下發不同Action導致系統分發邏輯不同的總結,該總結建立在閱讀過事件分發的原始碼上,如果沒有閱讀過原始碼的話,不建議閱讀該篇文章。如果有總結不對的地方,希望各位同行能夠指正,一起進步~
首先ViewGroup中的觸控處理邏輯如下:
void dispatchTouchEvent(){ if(onInterceptionTouchEvent()){ onDraw(); }else{ child.disptachTouchEvent(); } }
當一個觸控事件來臨的時候,首先由Activity接收到觸控事件,然後下發至DecorView,DecorView中根據Z軸位置由上至下進行傳遞事件處理:
- Activity -> DecorView -> ViewGroup ->....->View
當傳遞過程中沒有任何View消費事件,那麼事件由View->ViewGroup->Activity逆序返回,最終的事件由Activity處理,如果View消費了事件,那麼則分為兩種情況,這兩種情況可以從程式碼的角度中理解:
public boolean dispatchTouchEvent(MotionEvent ev){ ... //1. if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false; } } else { intercepted = true; } //2. if (!canceled && !intercepted){ //傳遞事件,構造mFirstTouchTarget } ... }
- 當在ACTION_DOWN時攔截,第二步是不會走的,也就意味著mFirstTouchTarget=null,在隨後的事件來臨的時候,由於mFirstTouchTarget==null,事件全權交由當前ViewGroup處理,子View就再也收不到觸控事件了。
- 當不在ACTION_DOWN時攔截,並且mFirstTouchTarget不為空,那麼這個時候子View會收到一個ACITON_CANCEL事件,然後後續事件都由ViewGroup處理了。
那麼通過這種情況,我們得知,當我們在處理滑動觸控衝突的時候,不應該在父ViewGroup中進行ACTION_DOWN的攔截操作,如果攔截了,子View根本不可能受到觸控事件;另外當父ViewGroup攔截中攔截了ACTION_MOVE操作後,實際上子View是會收到一個CANCALE事件的,通過該事件,我們能在子View中進行一