關於Android事件分發中onInterceptTouchEvent呼叫時機
阿新 • • 發佈:2019-02-08
首先,當一個down事件來臨的時候,viewgroup的dispachTouchEvent中會清除所有的上一個手勢的狀態
// Handle an initial down. if (actionMasked == MotionEvent.ACTION_DOWN) { // Throw away all previous state when starting a new touch gesture. // The framework may have dropped the up or cancel event for the previous gesture // due to an app switch, ANR, or some other state change.cancelAndClearTouchTargets(ev); resetTouchState(); }
關於事件攔截呼叫的原始碼:
// Check for interception. final boolean intercepted; 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 { // There are no touch targets and this action is not an initial down // so this view group continues to intercept touches. intercepted = true;
}
流程:先判斷是否是一個down事件或者是否有首次觸控目標,為false就是代表上一個down被自己消費了,所以這次肯定攔截下來自己處理。為true的話就是這個down事件第一次傳遞到該ViewGroup,然後獲得一個disallowIntercept值,關於mGroupFlags中該位掩碼的賦值在以下方法中發現
@Override public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) { // We're already in this state, assume our ancestors are too return; } if (disallowIntercept) { mGroupFlags |= FLAG_DISALLOW_INTERCEPT; } else { mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; } // Pass it up to our parent if (mParent != null) { mParent.requestDisallowInterceptTouchEvent(disallowIntercept); } }該方法設定了當前ViewGroup及以上所有ViewGroup的不允許攔截狀態掩碼,但是未發現View和ViewGroup中有過呼叫,應該是給擴充套件類呼叫的。也就是說當我們沒有特定需求的時候,ViewGroup的disallowIntercept狀態都是false的,那麼onInterceptTouchEvent()都會執行。即子控制元件響應了down動作後,只要沒有呼叫requestDisallowInterceptTouchEvent方法,後續事件父控制元件都允許攔截。
通過程式碼測試,父控制元件把up事件攔截,子控制元件會處理到down和move,但是沒有up觸發不了onClick。
結論:沒有請求父控制元件不攔截touch事件的時候,父控制元件式可以在子控制元件處理了down後把後續事件攔截的。