文章目录
Android 事件分发 系列文章目录
一、按下触摸事件记录
二、完整的触摸事件处理机制
三、ViewGroup | dispatchTouchEvent 方法返回
四、ViewGroup 事件分发相关源码
五、View 事件分发相关源码
一、按下触摸事件记录
在上一篇博客 【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 五 ) 中 , 着重分析了 ViewGroup 事件分发中 , 触摸事件没有被消费 , 或被父容器拦截的情况 ;
这里再分析下触摸事件被消费之后的 , 触摸事件记录过程 ;
触摸事件如果成功被消费 , 则 dispatchTransformedTouchEvent 方法返回 true ;
对应的会调用 addTouchTarget 方法 , 创建 TouchTarget 对象 , 赋值给 newTouchTarget 成员变量 ;
newTouchTarget = addTouchTarget(child, idBitsToAssign)
TouchTarget 代表了个触摸事件 , 每个 TouchTarget 中都封装了消费该触摸事件的 View 组件 ;
// The touched child view. // 当前 View 对象 public View child;
TouchTarget 经过优化后 , 以链表形式存储 , 每个 TouchTarget 都定义了一个 next 成员变量 , 指向下一个 TouchTarget 被消费的触摸事件 ;
// The next target in the target list. // 链表操作 , 该引用指向下一个触摸事件 public TouchTarget next;
相关源码 :
@UiThread public abstract class ViewGroup extends View implements ViewParent, ViewManager { @Override public boolean dispatchTouchEvent(MotionEvent ev) { ... // 正式开始分发触摸事件 // 处理以下两种情况 : // ① 情况一 : 子控件触摸事件返回 true // ② 情况二 : 子控件触摸事件返回 false if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { // Child wants to receive touch within its bounds. // 如果返回值为 true , 说明该事件已经被消费了 // 此时记录这个已经被消费的事件 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; } // 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(); } // 如果上述事件分发方法 dispatchTransformedTouchEvent 返回 true // 就会创建 newTouchTarget 值 , 该值不会为空 , 同时 mFirstTouchTarget 不为空 // 如果上述事件分发方法 dispatchTransformedTouchEvent 返回 false // 此时 newTouchTarget 值 , 就会为空 , 同时 mFirstTouchTarget 为空 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; } } } // 如果事件被消费 , 事件分发方法 dispatchTransformedTouchEvent 返回 true // 就会创建 newTouchTarget 值 , 该值不会为空 , 同时 mFirstTouchTarget 不为空 // 反之 // 如果上述事件分发方法 dispatchTransformedTouchEvent 返回 false // 此时 newTouchTarget 值 , 就会为空 , 同时 mFirstTouchTarget 为空 // // 还有一个逻辑就是 , 如果该事件被父容器拦截 , mFirstTouchTarget 也是 null 值 // 调用 dispatchTransformedTouchEvent , 但是传入的子组件时 null // 在 dispatchTransformedTouchEvent 方法中触发调用 if (child == null) 分支的 // handled = super.dispatchTouchEvent(event) 方法 , 调用父类的事件分发方法 // 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. TouchTarget predecessor = null; // TouchTarget target = mFirstTouchTarget; while (target != null) { // 链表式操作 final TouchTarget next = target.next; if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) { handled = true; } else { final boolean 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(); } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) { final int actionIndex = ev.getActionIndex(); final int idBitsToRemove = 1 << ev.getPointerId(actionIndex); removePointersFromTouchTargets(idBitsToRemove); } } if (!handled && mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1); } return handled; } /** * Adds a touch target for specified child to the beginning of the list. * Assumes the target child is not already present. */ private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) { final TouchTarget target = TouchTarget.obtain(child, pointerIdBits); target.next = mFirstTouchTarget; mFirstTouchTarget = target; return target; } }