1. 程式人生 > >Android中ViewGroup的事件分發結論記錄

Android中ViewGroup的事件分發結論記錄

開發十年,就只剩下這套架構體系了! >>>   

這裡記錄一下關於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中進行一