// 点击事件产生后,会直接调用dispatchTouchEvent分发方法
public boolean dispatchTouchEvent(MotionEvent ev) {
//代表是否消耗事件
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
//如果onInterceptTouchEvent()返回true则代表当前View拦截了点击事件
//则该点击事件则会交给当前View进行处理
//即调用onTouchEvent ()方法去处理点击事件
consume = onTouchEvent (ev) ;
} else {
//如果onInterceptTouchEvent()返回false则代表当前View不拦截点击事件
//则该点击事件则会继续传递给它的子元素
//子元素的dispatchTouchEvent()就会被调用,重复上述过程
//直到点击事件被最终处理为止
consume = child.dispatchTouchEvent (ev) ;
}
return consume;
}
总结
1、事件分发时由activity->viewgroup->view,依次向下传递,消费事件后,且事件不会往下传递,后续事件会继续分发到该view
2、事件不被消费,且事件停止传递,将事件回传给父控件的onTouchEvent处理,当前view仍然接受此事件的其他事件
3、拦截事件后,事件不会往下传递,自己处理事件,即执行自己的onTouchEvent();同事件列的其他事件都由该view处理;在同一个事件列中的onInterceptTouchEvent()该方法不会再次被调用。
4、不拦截事件,事件会继续往下传递,事件传递到子view ,后续事件序列让其处理
5、自己处理事件onToutchEvent(),事件不会继续传递,后续事件序列让其处理
6、不处理事件,将事件往上传递给父控件的onToutchEvent()处理,当前view不再接受此事件的其他事件
ViewGroup的dispatchTouchEvent()源码分析
// 发生ACTION_DOWN事件或者已经发生过ACTION_DOWN,并且将mFirstTouchTarget赋值,才进入此区域,主要功能是拦截器
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) {
//disallowIntercept:是否禁用事件拦截的功能(默认是false),即不禁用
//可以在子View通过调用requestDisallowInterceptTouchEvent方法对这个值进行修改,不让该View拦截事件
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
//默认情况下会进入该方法
if (!disallowIntercept) {
//调用拦截方法
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action);
} else {
intercepted = false;
}
} else {
// 当没有触摸targets,且不是down事件时,开始持续拦截触摸。
intercepted = true;
}
如果遍历所有子View或ViewGroup,都没有消费事件。ViewGroup会自己处理事件
如果子元素的dispatchTouchEvent()方法返回true,那么mFirstTouchTarget就会被赋值,同时跳出for循环
这一段的内容主要是为判断是否拦截。如果当前事件的MotionEvent.ACTION_DOWN,则进入判断,调用ViewGroup onInterceptTouchEvent()方法的值,判断是否拦截。如果mFirstTouchTarget != null,即已经发生过MotionEvent.ACTION_DOWN,并且该事件已经有ViewGroup的子View进行处理了,那么也进入判断,调用ViewGroup onInterceptTouchEvent()方法的值,判断是否拦截。如果不是以上两种情况,即已经是MOVE或UP事件了,并且之前的事件没有对象进行处理,则设置成true,开始拦截接下来的所有事件。 这也就解释了如果子View的onTouchEvent()方法返回false,那么接下来的一些列事件都不会交给他处理。如果VieGroup的onInterceptTouchEvent()第一次执行为true,则mFirstTouchTarget = null,则也会使得接下来不会调用onInterceptTouchEvent(),直接将拦截设置为true
addTouchTarget(child, idBitsToAssign);
内部完成mFirstTouchTarget被赋值。如果mFirstTouchTarget为空,将会让ViewGroup默认拦截所有操作
/* 从最底层的父视图开始遍历,
** 找寻newTouchTarget,即上面的mFirstTouchTarget
** 如果已经存在找寻newTouchTarget,说明正在接收触摸事件,则跳出循环。
*/
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = customOrder
? getChildDrawingOrder(childrenCount, i) : i;
final View child = (preorderedList == null)
? children[childIndex] : preorderedList.get(childIndex);
// 如果当前视图无法获取用户焦点,则跳过本次循环
if (childWithAccessibilityFocus != null) {
if (childWithAccessibilityFocus != child) {
continue;
}
childWithAccessibilityFocus = null;
i = childrenCount - 1;
}
//如果view不可见,或者触摸的座标点不在view的范围内,则跳过本次循环
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
newTouchTarget = getTouchTarget(child);
// 已经开始接收触摸事件,并退出整个循环。
if (newTouchTarget != null) {
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
//重置取消或擡起标志位
//如果触摸位置在child的区域内,则把事件分发给子View或ViewGroup
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// 获取TouchDown的时间点
mLastTouchDownTime = ev.getDownTime();
// 获取TouchDown的Index
if (preorderedList != null) {
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
//获取TouchDown的x,y座标
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
//添加TouchTarget,则mFirstTouchTarget != null。
newTouchTarget = addTouchTarget(child, idBitsToAssign);
//表示以及分发给NewTouchTarget
alreadyDispatchedToNewTouchTarget = true;
break;
}
详细查看view事件分发
onTouch->onTouchEvent->onClick优先执行顺序
view事件分发伪代码