// If the event targets the accessibility focused view and this is it, start // normal event dispatch. Maybe a descendant is what will handle the click. if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) { ev.setTargetAccessibilityFocus(false); }
// Handle an initial down. if (actionMasked == MotionEvent.ACTION_DOWN) { // 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) {// 事件流开始或者已经找到要分发的view finalbooleandisallowIntercept= (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { // 是否允许父view拦截 intercepted = onInterceptTouchEvent(ev); // 父View是否拦截 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; }
// If intercepted, start normal event dispatch. Also if there is already // a view that is handling the gesture, do normal event dispatch. if (intercepted || mFirstTouchTarget != null) { ev.setTargetAccessibilityFocus(false); }
// Update list of touch targets for pointer down, if needed. finalbooleansplit= (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; TouchTargetnewTouchTarget=null;// newTarget标识是否和原来的target有变化,来判断是否已经分发过了 booleanalreadyDispatchedToNewTouchTarget=false; if (!canceled && !intercepted) { // 不是取消事件,也不是拦截事件(如果是二者,那么不找新的target,直接进行分发,cancel分发给子view,拦截分发给自己)
// If the event is targeting accessibility focus we give it to the // view that has accessibility focus and if it does not handle it // we clear the flag and dispatch the event to all children as usual. // We are looking up the accessibility focused host to avoid keeping // state since these events are very rare. ViewchildWithAccessibilityFocus= ev.isTargetAccessibilityFocus() ? findChildWithAccessibilityFocus() : null;
if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { finalintactionIndex= ev.getActionIndex(); // always 0 for down finalintidBitsToAssign= split ? 1 << ev.getPointerId(actionIndex) : 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) {//viewgroup是不是空的 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();// 获取直接子View,而不是子孙View 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 there is a view that has accessibility focus we want it // to get the event first and if not handled we will perform a // normal dispatch. We may do a double iteration but this is // safer given the timeframe. if (childWithAccessibilityFocus != null) {// 如果有辅助View,那么我们就要确保先找到这个辅助View,然后从头开始正常分发 if (childWithAccessibilityFocus != child) { continue; } childWithAccessibilityFocus = null; i = childrenCount - 1; }
if (!canViewReceivePointerEvents(child) //如果view不可以接收触摸事件 且 事件坐标范围不在view内,那么跳过继续寻找 || !isTransformedTouchPointInView(x, y, child, null)) { ev.setTargetAccessibilityFocus(false); 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;// 找到了有意愿处理触摸事件的view,不再继续往下找 }
resetCancelNextUpFlag(child); if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {// 找到可以分发的,跳出循环 // Child wants to receive touch within its bounds. // 找到了,(注意,只有ACTION_DOWN才能进行到这一步,MOVE等事件在上一步就已经找好了 mLastTouchDownTime = ev.getDownTime(); if (preorderedList != null) { // childIndex points into presorted list, find original index for (intj=0; j < childrenCount; j++) { if (children[childIndex] == mChildren[j]) { mLastTouchDownIndex = j; break; } } } else { mLastTouchDownIndex = childIndex; } mLastTouchDownX = ev.getX(); mLastTouchDownY = ev.getY(); newTouchTarget = addTouchTarget(child, idBitsToAssign);// 新加入的touchTarget加入列表头 alreadyDispatchedToNewTouchTarget = true; break; }
// The accessibility focus didn't handle the event, so clear // the flag and do a normal dispatch to all children. ev.setTargetAccessibilityFocus(false); } 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;// 表明事件之前已经分发过了。所以有target记录 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 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { resetTouchState(); } elseif (split && actionMasked == MotionEvent.ACTION_POINTER_UP) { finalintactionIndex= ev.getActionIndex(); finalintidBitsToRemove=1 << ev.getPointerId(actionIndex); removePointersFromTouchTargets(idBitsToRemove); } }