ViewGroup 比View复杂
View相当予单独的 没什么好说的
但是 ViewGroup里面存在View
那就是正题来了 昨天已经分析了 今天就直接点 直接来到ViewGroup的
来个例子
布局
代码
默认状态 下 测试 点击按钮
结果出来了 发现 button点击失效了 变成 ontouch在父布局了 这说明
onclick事件肯定在ontouch之后的
上一节 说了 事件触摸会调用 该控件的
dispatchTouchEvent方法 所以这里猜想
某个控件 会先去找到该控件的父控件 在父控件里面找
dispatchTouchEvent这个方法 而过没有 在找这个父控件的父控件的这个方法 一直找下去 最后 找到了ViewGroup 里面
这和前面的是一样的 前面的是一个View控件 中间没有经过ViewGroup 如果中间经过ViewGroup 那就是进入ViewGroup的dispatchTouchEvent 方法
dispatchTouchEvent 这个方法
进去看了看 我的天 好几百行 但是我们只看我们要看的
会进去 这个onInterceptTouchEvent(ev) 方法 因为不太清楚 上面那个条件是什么 看字面意思
disallowIntercept 这个 是 不允许中断
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev); //允许中断 进入这个
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
进去这个方法 我一手一抖
啥情况 这不是intercepted=false 肯定的啦 不管上面条件如何
刚才实验 我们在
onInterceptTouchEvent 这个方法 返回true 就屏蔽了所有的子View的点击事件 我们以这个intercepted 的值为引入点 继续往下看
来到这里 因为 默认是 false 只有为false才会进入这个判断 所以为true的时候进不去 子View的事件都在这个判断里面 我们进去看看
这一段代码 挺长的
if (!canceled && !intercepted) {
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
final int actionIndex = ev.getActionIndex(); // always 0 for down
final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
: TouchTarget.ALL_POINTER_IDS;
// Clean up earlier touch targets for this pointer id in case they
// have become out of sync.
removePointersFromTouchTargets(idBitsToAssign);
final int childrenCount = mChildrenCount;
if (newTouchTarget == null && childrenCount != 0) {
final float x = ev.getX(actionIndex);
final float y = ev.getY(actionIndex);
// Find a child that can receive the event.
// Scan children from front to back.
final View[] children = mChildren;
final boolean customOrder = isChildrenDrawingOrderEnabled();
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = customOrder ?
getChildDrawingOrder(childrenCount, i) : i;
final View child = children[childIndex];
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
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);
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// Child wants to receive touch within its bounds.
mLastTouchDownTime = ev.getDownTime();
mLastTouchDownIndex = childIndex;
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
}
}
dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)
这句 我们 再进去 看一下 因为 确实代码不知道是什么 但是我们可以 带着想法去看
我们这里熟悉的只有dispatch~~~的方法 看到这个 最像
其实 网上很多人都研究 过 不过我的是 比较新的源码 网上都是旧的 还是很多不同的
我们进去这个方法 上面写了 意思就是 当前view 去处理事件 果然 看到 这个方法 dispatchTouchEvent 这里 我们可以看到 如果child不为空 那就是子view自己dispatch~~ 如果为空 那就是父布局来执行了
所以 现在 又回到昨天的 View的分发事件 点击了效果出来了是返回了true 如果返回false 事件不会被消费
然后继续 看 这里返回true 那么 这句话被执行 这句话 我英语巨水 都知道这是 已经被分发到一个新目标 就是 ViewGroup分发给了子View
=
当这个=true的时候
不会进入上面 那段很长的代码 直接来到这里
这个方法 肯定是没有child啦 因为child是那个条件为false才有机会有 所以这里肯定是被父控件布局调用
所以现在 可以解释我们刚才的返回 true的被父类(ViewGroup的父类是View 相当于现在这个ViewGroup只是一个View了) 给dispatch~~ 了
就是
onInterceptTouchEvent
这个方法返回false 才有机会进入一个判断 去得到子View 然后再分发的时候会给子View去分发
返回true就没有得到子View 分发的时候 自己实现
说道这里 其实 我们在运用这个知识点的时候 只需要对 父控件的
onInterceptTouchEvent 这个方法做处理就行了
最后来一个 结构图
画的有点丑 有点简陋
以前其实分析过 刚好找到那张图了 也一起拿上来吧
写这些 其实 没什么意思 很枯燥 下次 就拿实例 来写