1)DOWN事件触发时重置标志位;
2)判断是否拦截事件(根据FLAG_DISALLOW_INTERCEPT标志和onInterceptTouchEvent返回值);
3)遍历子View寻找能处理事件的View,通过dispatchTransformedTouchEvent询问子View;
4)将处理事件的子View保存到mFirstTouchTarget链表;
5)后续事件根据mFirstTouchTarget和拦截状态决定分发路径。当父容器拦截时,会向子View发送CANCEL事件并清空mFirstTouchTarget。整个过程实现了从父容器到子View的事件分发与拦截机制
- 置空标志位置
// 在DOWN事件的时候会置空标志位置
if (actionMasked == MotionEvent.ACTION_DOWN) {
// 清掉旧 TouchTarget,清空mFirstTouchTarget
cancelAndClearTouchTargets(ev);
// 重置 FLAG_DISALLOW_INTERCEPT 等
resetTouchState();
}
private void cancelAndClearTouchTargets(MotionEvent event) {
//清空mFirstTouchTarget
clearTouchTargets();
}
//清空mFirstTouchTarget
private void clearTouchTargets() {
ViewGroup.TouchTarget target = mFirstTouchTarget;
if (target != null) {
do {
ViewGroup.TouchTarget next = target.next;
target.recycle();
target = next;
} while (target != null);
mFirstTouchTarget = null;
}
}
- 第一块代码,判断事件是否由父容器拦截
//是否拦截标志
final boolean intercepted;
//判断是否是DOWN事件,或者是mFirstTouchTarget第一个处理事件的View
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
//requestDisallowInterceptTouchEvent决定这里的属性,true这里为true,false这里为false
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;
}
- 第二块代码,决定是由父容器还是子View处理事件
ViewGroup.TouchTarget newTouchTarget = null;
boolean alreadyDispatchedToNewTouchTarget = false;
//判断是否是拦截事件
if (!canceled && !intercepted) {
//单手指DOWN,多手指ACTION_POINTER_DOWN,鼠标DOWN ACTION_HOVER_MOVE
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
//这里newTouchTarget=null,判断是否存在子View
if (newTouchTarget == null && childrenCount != 0) {
final float x =
isMouseEvent ? ev.getXCursorPosition() : ev.getX(actionIndex);
final float y =
isMouseEvent ? ev.getYCursorPosition() : ev.getY(actionIndex);
// Find a child that can receive the event.
// Scan children from front to back.
final ArrayList<View> preorderedList = buildTouchDispatchChildList();
final boolean customOrder = preorderedList == null
&& isChildrenDrawingOrderEnabled();
final View[] children = mChildren;
//开始遍历子View
for (int i = childrenCount - 1; i >= 0; i--) {
//确定该点位落在那个View
if (!child.canReceivePointerEvents()
|| !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;
}
resetCancelNextUpFlag(child);
//找到落点位置的View,开始询问View是否处理事件
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();
//有View处理事件,开始修改标志位置,将mFirstTouchTarget设置为当前处理的View,newTouchTarget = mFirstTouchTarget
newTouchTarget = addTouchTarget(child, idBitsToAssign);
//表示down事件已经有View处理
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();
}
}
//标准位进行赋值,mFirstTouchTarget = target, target.next = null,mFirstTouchTarget.next = null
private ViewGroup.TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
final ViewGroup.TouchTarget target = ViewGroup.TouchTarget.obtain(child, pointerIdBits);
//这里mFirstTouchTarget在DOWN的时候置空了,这里为空
target.next = mFirstTouchTarget;
//mFirstTouchTarget赋值为当前处理事件的View
mFirstTouchTarget = target;
return target;
}
}
dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
// Perform any necessary transformations and dispatch.
if (child == null) {
handled = super.dispatchTouchEvent(transformedEvent);
} else {
//询问子View是否处理事件
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
transformedEvent.offsetLocation(offsetX, offsetY);
if (! child.hasIdentityMatrix()) {
transformedEvent.transform(child.getInverseMatrix());
}
handled = child.dispatchTouchEvent(transformedEvent);
}
}
- 第三块代码,对其他事件继续处理
// Check for cancelation.
final boolean canceled = resetCancelNextUpFlag(this)
|| actionMasked == MotionEvent.ACTION_CANCEL;
//没有子View处理事件,将事件交个父容器,询问父容器是否需要处理事件
if (mFirstTouchTarget == null) {
//注释1:canceled = false
handled = dispatchTransformedTouchEvent(ev, canceled, null,
ViewGroup.TouchTarget.ALL_POINTER_IDS);
} else {
ViewGroup.TouchTarget predecessor = null;
ViewGroup.TouchTarget target = mFirstTouchTarget;
//mFirstTouchTarget = target, target.next = null,mFirstTouchTarget.next = null
//这里不为空,执行该方法
while (target != null) {
//next 未空,下一次将不执行
final ViewGroup.TouchTarget next = target.next;
//DOWN alreadyDispatchedToNewTouchTarget = true 有View处理事件 alreadyDispatchedToNewTouchTarget = true,newTouchTarget = target = mFirstTouchTarget
if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
handled = true;
} else {
//DOWN事件没有处理获取其他事件 alreadyDispatchedToNewTouchTarget = false
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
//注释2:对已经处理的事件进行分发
if (dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)) {
handled = true;
}
//当MOVE的时候,父容器拦截事件,将事件置为CANCEL事件后,将mFirstTouchTarget置空
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);
}
//注释1:
//canceled = false
handled = dispatchTransformedTouchEvent(ev, canceled, null,
ViewGroup.TouchTarget.ALL_POINTER_IDS);
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
//child = null,询问父容器是否处理事件
if (child == null) {
handled = super.dispatchTouchEvent(transformedEvent);
} else {
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
transformedEvent.offsetLocation(offsetX, offsetY);
if (! child.hasIdentityMatrix()) {
transformedEvent.transform(child.getInverseMatrix());
}
handled = child.dispatchTouchEvent(transformedEvent);
}
}
//注释2:
final boolean cancelChild = resetCancelNextUpFlag(target.child)
|| intercepted;
dispatchTransformedTouchEvent(ev, cancelChild,
target.child, target.pointerIdBits)
cancelChild =false;
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
if (child == null) {
handled = super.dispatchTouchEvent(transformedEvent);
} else {
//询问子View 是否处理事件
final float offsetX = mScrollX - child.mLeft;
final float offsetY = mScrollY - child.mTop;
transformedEvent.offsetLocation(offsetX, offsetY);
if (! child.hasIdentityMatrix()) {
transformedEvent.transform(child.getInverseMatrix());
}
handled = child.dispatchTouchEvent(transformedEvent);
}
}
cancelChild = true;
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
//父类View拦截了事件,将事件改成cancel下发给View
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;
}
}
- 事件分发场景1
DOWN事件,
条件1:父容器onInterceptTouchEvent返回false,
条件2:子View dispatchTouchEvent返回false,
条件3:父容器onTouch返回false,
- 事件分发2
DOWN事件,
条件1:父容器onInterceptTouchEvent返回false,
条件2:子View dispatchTouchEvent返回true,
条件3:父容器onTouch返回false,
- 事件分发3
DOWN事件,
条件1:父容器onInterceptTouchEvent返回false,
条件2:子View dispatchTouchEvent返回false,
条件3:父容器onTouch返回true,
- 事件分发4
DOWN事件,
条件1:父容器onInterceptTouchEvent返回false,
条件2:子View dispatchTouchEvent返回true,
条件3:父容器onTouch返回true,
同事件分发2,会首先响应子View的事件处理,响应后不再响应父容器的事件响应
- 事件分发5
如果DOWN事件是父容器拦截了,那么子View将不会再收到事件
DOWN事件,
条件1:父容器onInterceptTouchEvent返回true,
条件2:子View dispatchTouchEvent返回true或者false,
条件3:父容器onTouch返回true或者false,
- 事件分发6
条件1:父容器onInterceptTouchEvent返回false,
条件2:子View requestDisallowInterceptTouchEvent设置成true
条件3:子View dispatchTouchEvent返回true
条件4:父容器onTouch返回true或者false,
MOVE事件1,
条件1:父容器onInterceptTouchEvent返回true,
条件2:子View requestDisallowInterceptTouchEvent设置成false
条件3:子View dispatchTouchEvent返回true
条件4:父容器onTouch返回true,
MOVE事件2,
条件1:父容器onInterceptTouchEvent返回true,
条件2:requestDisallowInterceptTouchEvent设置成false
条件3:子View dispatchTouchEvent返回true
条件4:父容器onTouch返回true,
MOVE事件3,
条件1:父容器onInterceptTouchEvent返回true,
条件2:requestDisallowInterceptTouchEvent设置成false
条件3:子View dispatchTouchEvent返回true
条件4:父容器onTouch返回true,
子View只要在DOWN事件返回true就可以接收其他所有事件
在DOWN事件返回true的时候,会把响应的View保存到派发链表mFirstTouchTarget中,接下来的事件,只要父类不拦截,都会派发事件给当前mFirstTouchTarget保存的View,如果父容器有拦截,就会传递CANCEL事件给mFirstTouchTarget保存的View,并且把mFirstTouchTarget置空,以后的所有事件都会传给父容器