// 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. finalboolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { finalbooleandisallowIntercept= (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; }
// Check for cancelation. finalbooleancanceled= resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;
// Update list of touch targets for pointer down, if needed. finalbooleansplit= (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; TouchTargetnewTouchTarget=null; booleanalreadyDispatchedToNewTouchTarget=false; if (!canceled && !intercepted) { if (actionMasked == MotionEvent.ACTION_DOWN) { finalintactionIndex= ev.getActionIndex(); // always 0 for down finalintidBitsToAssign= TouchTarget.ALL_POINTER_IDS;
// Clean up earlier touch targets for this pointer id in case they // have become out of sync. removePointersFromTouchTargets(idBitsToAssign);
finalintchildrenCount= mChildrenCount; if (newTouchTarget == null && childrenCount != 0) { finalfloatx= ev.getX(actionIndex); finalfloaty= ev.getY(actionIndex); // Find a child that can receive the event. // Scan children from front to back. final ArrayList<View> preorderedList = buildTouchDispatchChildList(); finalbooleancustomOrder= preorderedList == null && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (inti= childrenCount - 1; i >= 0; i--) { finalintchildIndex= getAndVerifyPreorderedIndex( childrenCount, i, customOrder); finalViewchild= getAndVerifyPreorderedView( preorderedList, children, childIndex);
if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { continue; }
newTouchTarget = getTouchTarget(child); if (newTouchTarget != null) { // Child is already receiving touch within its bounds. // Give it the new pointer in addition to the ones it is handling. newTouchTarget.pointerIdBits |= idBitsToAssign; break; }
resetCancelNextUpFlag(child); if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { // Child wants to receive touch within its bounds. newTouchTarget = addTouchTarget(child, idBitsToAssign); alreadyDispatchedToNewTouchTarget = true; break; } } if (preorderedList != null) preorderedList.clear(); }
if (newTouchTarget == null && mFirstTouchTarget != null) { // Did not find a child to receive the event. // Assign the pointer to the least recently added target. newTouchTarget = mFirstTouchTarget; while (newTouchTarget.next != null) { newTouchTarget = newTouchTarget.next; } newTouchTarget.pointerIdBits |= idBitsToAssign; } } }
// Dispatch to touch targets. if (mFirstTouchTarget == null) { // No touch targets so treat this as an ordinary view. handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS); } else { // Dispatch to touch targets, excluding the new touch target if we already // dispatched to it. Cancel touch targets if necessary. TouchTargetpredecessor=null; TouchTargettarget= mFirstTouchTarget; while (target != null) { finalTouchTargetnext= target.next; if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true; } else { finalbooleancancelChild= resetCancelNextUpFlag(target.child) || intercepted; if (dispatchTransformedTouchEvent(ev, cancelChild, target.child, target.pointerIdBits)) { handled = true; } if (cancelChild) { if (predecessor == null) { mFirstTouchTarget = next; } else { predecessor.next = next; } target.recycle(); target = next; continue; } } predecessor = target; target = next; } }
// Update list of touch targets for pointer up or cancel, if needed. if (canceled || actionMasked == MotionEvent.ACTION_UP) { resetTouchState(); }
// 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. finalboolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { finalbooleandisallowIntercept= (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; }
// Update list of touch targets for pointer down, if needed. finalbooleansplit= (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; TouchTargetnewTouchTarget=null; booleanalreadyDispatchedToNewTouchTarget=false;
如果没有被取消,也没有被拦截,那么就要尝试分发给子View了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
if (!canceled && !intercepted) { if (actionMasked == MotionEvent.ACTION_DOWN) { finalintactionIndex= ev.getActionIndex(); // always 0 for down finalintidBitsToAssign= TouchTarget.ALL_POINTER_IDS;
// Clean up earlier touch targets for this pointer id in case they // have become out of sync. removePointersFromTouchTargets(idBitsToAssign);
finalintchildrenCount= mChildrenCount; if (newTouchTarget == null && childrenCount != 0) { // Part A }
if (newTouchTarget == null && mFirstTouchTarget != null) { // Part B } } }
if (newTouchTarget == null && childrenCount != 0) { finalfloatx= ev.getX(actionIndex); finalfloaty= ev.getY(actionIndex); // Find a child that can receive the event. // Scan children from front to back. final ArrayList<View> preorderedList = buildTouchDispatchChildList(); finalbooleancustomOrder= preorderedList == null && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (inti= childrenCount - 1; i >= 0; i--) { // ... } if (preorderedList != null) preorderedList.clear(); }
finalintchildIndex= getAndVerifyPreorderedIndex( childrenCount, i, customOrder); finalViewchild= getAndVerifyPreorderedView( preorderedList, children, childIndex);
if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { continue; }
newTouchTarget = getTouchTarget(child); if (newTouchTarget != null) { // Child is already receiving touch within its bounds. // Give it the new pointer in addition to the ones it is handling. newTouchTarget.pointerIdBits |= idBitsToAssign; break; }
resetCancelNextUpFlag(child); if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { // Child wants to receive touch within its bounds. newTouchTarget = addTouchTarget(child, idBitsToAssign); alreadyDispatchedToNewTouchTarget = true; break; }
// Dispatch to touch targets. if (mFirstTouchTarget == null) { // No touch targets so treat this as an ordinary view. handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS); } else { // ... }