// Always enqueue the input event in order, regardless of its time stamp. // We do this because the application or the IME may inject key events // in response to touch events and we want to ensure that the injected keys // are processed in the order they were received and we cannot trust that // the time stamp of injected events are monotonic. // 将新事件加入到未处理事件链中 QueuedInputEvent last = mPendingInputEventTail; if (last == null) { mPendingInputEventHead = q; mPendingInputEventTail = q; } else { last.mNext = q; mPendingInputEventTail = q; } mPendingInputEventCount += 1;
// Handle an initial down.一次新的点击事件,则重制View状态 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) { // 子View可以通过requestDisallowInterceptTouchEvent更改flag使得父控件始终不拦截事件 finalboolean 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; }
// Clean up earlier touch targets for this pointer id in case they // have become out of sync. // down事件表示该触控点事件序列是一个新的序列 // 清除之前绑定到到该触控id的TouchTarget removePointersFromTouchTargets(idBitsToAssign);
finalint childrenCount = mChildrenCount; if (newTouchTarget == null && childrenCount != 0) { finalfloat x = ev.getX(actionIndex); finalfloat y = ev.getY(actionIndex); // Find a child that can receive the event. // Scan children from front to back. // View中可以配置z属性导致children数组中的顺序并不是实际的从前到后 // 根据z轴将子View从前到后排序成List final ArrayList<View> preorderedList = buildTouchDispatchChildList(); finalboolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; for (int i = childrenCount - 1; i >= 0; i--) { finalint childIndex = getAndVerifyPreorderedIndex( childrenCount, i, customOrder); // 依次取出View final View child = getAndVerifyPreorderedView( preorderedList, children, childIndex);
// 判断Child的可见性和动画状态是否能接受事件 if (!canViewReceivePointerEvents(child) // 判断这个点是否在View中 || !isTransformedTouchPointInView(x, y, child, null)) { ev.setTargetAccessibilityFocus(false); // 如果View不符合条件直接跳出本次循环,找下一个View continue; } // 如果这个View已经在TouchTarget链中,则更新新的触控点id 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); // 将事件发送给这个child,如果是多点则根据id拆分Event if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { // Child wants to receive touch within its bounds. mLastTouchDownTime = ev.getDownTime(); if (preorderedList != null) { // childIndex points into presorted list, find original index for (int j = 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); 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. // 没有子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. TouchTarget predecessor = null; TouchTarget target = mFirstTouchTarget; while (target != null) { final TouchTarget next = target.next; // 如果是Down事件,可能已经被消费 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true; } else { finalboolean cancelChild = 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) { finalint actionIndex = ev.getActionIndex(); finalint idBitsToRemove = 1 << ev.getPointerId(actionIndex); // 如果是Up事件,则根据id将View移出链 removePointersFromTouchTargets(idBitsToRemove); } }
privatebooleandispatchTransformedTouchEvent(MotionEvent event, boolean cancel, View child, int desiredPointerIdBits){ finalboolean handled;
// Canceling motions is a special case. We don't need to perform any transformations // or filtering. The important part is the action, not the contents. finalint oldAction = event.getAction(); if (cancel || oldAction == MotionEvent.ACTION_CANCEL) { event.setAction(MotionEvent.ACTION_CANCEL); if (child == null) { handled = super.dispatchTouchEvent(event); } else { handled = child.dispatchTouchEvent(event); } event.setAction(oldAction); return handled; }
// Calculate the number of pointers to deliver. // 获取存放全部的点id的int finalint oldPointerIdBits = event.getPointerIdBits(); // 取出desired的那一位的点id finalint newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
// If for some reason we ended up in an inconsistent state where it looks like we // might produce a motion event with no pointers in it, then drop the event. // 如果全部的点信息中与desired的那一位的点id不同,则丢弃该事件 if (newPointerIdBits == 0) { returnfalse; }
// If the number of pointers is the same and we don't need to perform any fancy // irreversible transformations, then we can reuse the motion event for this // dispatch as long as we are careful to revert any changes we make. // Otherwise we need to make a copy. final MotionEvent transformedEvent; // 如果全部点信息与目标点信息相同,说明当前只有一个点触摸 if (newPointerIdBits == oldPointerIdBits) { if (child == null || child.hasIdentityMatrix()) { if (child == null) { handled = super.dispatchTouchEvent(event); } else { finalfloat offsetX = mScrollX - child.mLeft; finalfloat offsetY = mScrollY - child.mTop; event.offsetLocation(offsetX, offsetY);
if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } // 获取action类型 finalint actionMasked = event.getActionMasked(); // 如果是down事件,停止正在的滚动 if (actionMasked == MotionEvent.ACTION_DOWN) { // Defensive cleanup for new gesture stopNestedScroll(); }
if (onFilterTouchEventForSecurity(event)) { if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { result = true; } //noinspection SimplifiableIfStatement ListenerInfo li = mListenerInfo; // 先判断mOnTouchListener是否消费 if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } // 如果mOnTouchListener不消费的话则判断onTouchEvent是否消费 if (!result && onTouchEvent(event)) { result = true; } }
// Clean up after nested scrolls if this is the end of a gesture; // also cancel it if we tried an ACTION_DOWN but we didn't want the rest // of the gesture. if (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL || (actionMasked == MotionEvent.ACTION_DOWN && !result)) { stopNestedScroll(); }