https://www.cnblogs.com/chengxuyinli/p/9979826.html
上面一篇文章重要的是伪代码部分
这篇文章 viewgroup有段伪代码有些问题 更改如下
// ViewGroup中该方法的核心部分伪代码
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!onInterceptTouchEvent(ev)) {
boolean handled = child.dispatchTouchEvent(ev);
//不拦截,则传给子View进行分发处理
if (!handled) {
return onTouchEvent(ev);
} else {
return true;
}
//不拦截,则传给子View进行分发处理
} else {
return onTouchEvent(ev); //拦截事件,交由自身对象的onTouchEvent方法处理
}
}
"为什么子view 没有处理action_down的时候 后续都收不到触摸事件了" 以下一段也是伪代码,先看代码下方解释。
// mFirstTouchTarget 可以理解为存储可以处理Touch事件的子View(不包括自身)的数据结构
private TouchTarget mFirstTouchTarget;
public boolean dispatchTouchEvent(MotionEvent ev) {
// 是否中断
final boolean intercepted;
// 仅在ACTION_DOWN 和 已确定处理的子View时 调用,一旦onInterceptTouchEvent返回true,
//则后续将不会在被调用和接收事件。后面会讲返回true后,mFirstTouchTarget会被为null;
//1
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
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;
}
// 如果不被拦截,在ACTION_DOWN事件处理中遍历所有的子View,找寻可以处理Touch事件的目标子View
// 然后封装到mFirstTouchTarget,如果子View的dispatchTouchEvent返回true,则认为是目标子View;
//2
if(!intercepted){
if (action == MotionEvent.ACTION_DOWN) {
//循环遍历直到找到愿意处理这个down事件的孩子
for(View child:childs){
if(child.dispatchTouchEvent(MotionEvent ev)){
mFirstTouchTarget = addTouchTarget(child);
break;
}
}
}
boolean handled;
// 如果mFirstTouchTarget == null,调用自身onTouchEvent()
//3
if(mFirstTouchTarget == null){
handled=onTouchEvent(ev);
}else{
// 应上面的逻辑,如果ACTION_MOVE传递过程中被拦截,则将mFirstTouchTarget置为null,并传递一个cancel事件,
// 告诉目标子View当前动作被取消了,后续事件将不会再次被传递;
//4
if (intercepted){
ev.action=MotionEvent.ACTION_CANCEL;
handled=mFirstTouchTarget.child.dispatchTouchEvent(ev);
mFirstTouchTarget=null;
}else {
//5
// 调用目标子view的dispatchTouchEvent,这也是为什么,上面结论所述的,dispatchTouchEvent/onTouchEvent
// 在ACTION_DOWN事件返回true,不管子View返回什么值,都能收到后续事件,会出现所谓控制“失效”的现象。
handled=mFirstTouchTarget.child.dispatchTouchEvent(ev);
}
}
retrun handled;
}
不用看那么多细节 想那么多情况 主要考虑 "为什么子view 没有处理action_down的时候 后续都收不到触摸事件了"
一 对于onInterceptTouchEvent方法走了默认逻辑的情况
第一次是action_down :走到1处, if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null)判断走的是true逻辑,viewgroup的onInterceptTouchEvent默认reture false,所以intercepted=false,在2处就会遍历调用childs的dispatchTouchEvent,找有没有孩子愿意处理这个事件,
a.(down如果有孩子处理,dispatchTouchEvent会返回true,mFirstTouchTarget.child就赋值为这个孩子的指针。那么3处就不会调用onTouchEvent了。然后4,5先不看。下一个event来,,viewgroup的onInterceptTouchEvent默认reture false,此时就没有2处遍历找能处理该事件的孩子的过程了(只在down的时候找,下次直接就交给down找到的孩子处理即mFirstTouchTarget.child)在3处判断mFirstTouchTarget此时不为空,intercepted=false,就走了5处的mFirstTouchTarget.child.dispatchTouchEvent(ev)。)
b.(down如果没有孩子处理,mFirstTouchTarget=null,3处就走了这一层的onTouchEvent了,下个事件来了,1处也不拦截了(没必要了 孩子也不处理),3那直接走这一层的onTouchEvent了)。
二,自己重写onInterceptTouchEvent方法的时候
down事件的时候就拦截了,那么后面的事件子view都收不到了
不是所有的View都有机会响应事件的 在Viewgroup的dispatchTouchEvent方法会倒序的遍历所有的childview 调用他们的方法区查看触摸点是不是在childview的触区内,是的话才传。
网友评论