一般的触摸事件传递顺序是ViewGroupRoot -> ViewGroupA -> View这样的。现在如果ViewGroupRoot下有两个同级的ViewGroupA和ViewGroupB,且两者宽高均为match_parent,那么请问这时的触摸事件传递顺序是怎样的?ViewGroupA和ViewGroupB谁先收到触摸事件?
小伙看你根骨奇佳,潜力无限,来学PHP伐。
打log或者debug只是知道结果却不知道为何, 我简单分析下决定这个传递顺序的逻辑触摸事件的传递顺序的逻辑应该在父控件的dispatchTouchEvent()方法中, 不同的父控件这个方法有可能不一样, 如果父控件的这个方法的实现改变了, 有可能会改变这个顺序.不过一般不会改的, 所以我们只看ViewGroup的实现, 看源码, 很容易找到把触摸事件传递给子控件的那部分代码, 基本变量命名出现child那堆就是了, 关键的逻辑应该是下面几行dispatchTouchEvent()方法中, 不同的父控件这个方法有可能不一样, 如果父控件的这个方法的实现改变了, 有可能会改变这个顺序.不过一般不会改的, 所以我们只看ViewGroup的实现, 看源码, 很容易找到把触摸事件传递给子控件的那部分代码, 基本变量命名出现child那堆就是了, 关键的逻辑应该是下面几行
dispatchTouchEvent()
ViewGroup
final int childrenCount = mChildrenCount; if (newTouchTarget == null && childrenCount != 0) { // 省略部分代码 final ArrayList<View> preorderedList = buildOrderedChildList(); final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); final View[] children = mChildren; 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); // 省略一堆后续判断 } }
这里可以明确看到定义了一个变量final View child, 这个就是事件将要传递的子控件, 当然后面还要经过一些判断才会把事件分发给它, 不过这里不关心了.
final View child
决定这个child的实例的逻辑是final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex);,关键的参数有两个, preorderedList和childIndex, 到这里基本可以确定触摸事件的分发顺序就是这两个参数决定的了.
child
final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex);
preorderedList
childIndex
接着看preorderedList, 是调用了方法buildOrderedChildList(), 这个方法的代码就不贴出来了, 如果你没有对子控件设置elevation或者translationZ, 那么就会返回空, 如果设置了的话那么返回一个根据Z轴排序的列表, 一般情况下都是没有设置的, 如果你设置了Z轴的值, 那么在Z轴的值越大就越优先分发事件.
buildOrderedChildList()
然后看childIndex, 一般情况下这个值就是xml文件中定义的顺序了, 不过我们可以通过方法getChildDrawingOrder()和setChildrenDrawingOrderEnabled(boolean enabled)来自定义子控件的绘制顺序, 如果你设置setChildrenDrawingOrderEnabled(true)那么isChildrenDrawingOrderEnabled()就会返回true, 导致customOrder变量在preorderedList为null的情况下是true, 接着就会调用getChildDrawingOrder()方法来获取当前事件分发的子控件的index.
getChildDrawingOrder()
setChildrenDrawingOrderEnabled(boolean enabled)
setChildrenDrawingOrderEnabled(true)
isChildrenDrawingOrderEnabled()
true
customOrder
总结, 你点击的区域有两个View, A和B, 它们大小相同, 位置重合
如果你对A或B设置了elevation或者translationZ, 那么会先分发给Z轴上值较大的View, 不设置的View默认是0, 此时index只能是xml上添加的顺序
如果你没有设置Z轴的值, 设置了setChildrenDrawingOrderEnabled(true)和实现了父控件的getChildDrawingOrder() rrreee
如果你什么都没干, 就是正常使用, 那么分发顺序就是子控件在xml中的顺序的倒序, 就是后添加的先分发, 实际上如果两个控件重合了, 你看到的也是后添加的控件, 那么自然点击事件也是先分发给后添加的控件了
大致是这样, 有错欢迎指正.
我觉得是随机的(猜测),这种问题,你可以打个log或debug看下就知道了啊、
按你的描述,是上面那个先获得触摸事件,如果上面的那个不处理就会传给下面的viewgroup
打log或者debug只是知道结果却不知道为何, 我简单分析下决定这个传递顺序的逻辑
触摸事件的传递顺序的逻辑应该在父控件的
dispatchTouchEvent()
方法中, 不同的父控件这个方法有可能不一样, 如果父控件的这个方法的实现改变了, 有可能会改变这个顺序.不过一般不会改的, 所以我们只看ViewGroup
的实现, 看源码, 很容易找到把触摸事件传递给子控件的那部分代码, 基本变量命名出现child那堆就是了, 关键的逻辑应该是下面几行dispatchTouchEvent()
方法中, 不同的父控件这个方法有可能不一样, 如果父控件的这个方法的实现改变了, 有可能会改变这个顺序.不过一般不会改的, 所以我们只看ViewGroup
的实现, 看源码, 很容易找到把触摸事件传递给子控件的那部分代码, 基本变量命名出现child那堆就是了, 关键的逻辑应该是下面几行这里可以明确看到定义了一个变量
final View child
, 这个就是事件将要传递的子控件, 当然后面还要经过一些判断才会把事件分发给它, 不过这里不关心了.决定这个
child
的实例的逻辑是final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex);
,关键的参数有两个,
preorderedList
和childIndex
, 到这里基本可以确定触摸事件的分发顺序就是这两个参数决定的了.接着看
preorderedList
, 是调用了方法buildOrderedChildList()
, 这个方法的代码就不贴出来了, 如果你没有对子控件设置elevation或者translationZ, 那么就会返回空, 如果设置了的话那么返回一个根据Z轴排序的列表, 一般情况下都是没有设置的, 如果你设置了Z轴的值, 那么在Z轴的值越大就越优先分发事件.然后看
childIndex
, 一般情况下这个值就是xml文件中定义的顺序了, 不过我们可以通过方法getChildDrawingOrder()
和setChildrenDrawingOrderEnabled(boolean enabled)
来自定义子控件的绘制顺序, 如果你设置setChildrenDrawingOrderEnabled(true)
那么isChildrenDrawingOrderEnabled()
就会返回true
, 导致customOrder
变量在preorderedList
为null的情况下是true
, 接着就会调用getChildDrawingOrder()
方法来获取当前事件分发的子控件的index.总结, 你点击的区域有两个View, A和B, 它们大小相同, 位置重合
如果你对A或B设置了elevation或者translationZ, 那么会先分发给Z轴上值较大的View, 不设置的View默认是0, 此时index只能是xml上添加的顺序
如果你没有设置Z轴的值, 设置了
这里可以明确看到定义了一个变量setChildrenDrawingOrderEnabled(true)
和实现了父控件的getChildDrawingOrder()
rrreeefinal View child
, 这个就是事件将要传递的子控件, 当然后面还要经过一些判断才会把事件分发给它, 不过这里不关心了.🎜 🎜决定这个child
的实例的逻辑是final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex);
,🎜关键的参数有两个,preorderedList
和childIndex
, 到这里基本可以确定触摸事件的分发顺序就是这两个参数决定的了.🎜 🎜接着看preorderedList
, 是调用了方法buildOrderedChildList()
, 这个方法的代码就不贴出来了, 如果你没有对子控件设置elevation或者translationZ, 那么就会返回空, 如果设置了的话那么返回一个根据Z轴排序的列表, 一般情况下都是没有设置的, 如果你设置了Z轴的值, 那么在Z轴的值越大就越优先分发事件.🎜 🎜然后看childIndex
, 一般情况下这个值就是xml文件中定义的顺序了, 不过我们可以通过方法getChildDrawingOrder()
和setChildrenDrawingOrderEnabled(boolean enabled)
来自定义子控件的绘制顺序, 如果你设置setChildrenDrawingOrderEnabled(true)
那么isChildrenDrawingOrderEnabled()
就会返回true
, 导致customOrder
变量在preorderedList
为null的情况下是true
, 接着就会调用getChildDrawingOrder()
方法来获取当前事件分发的子控件的index.🎜 🎜总结, 你点击的区域有两个View, A和B, 它们大小相同, 位置重合🎜setChildrenDrawingOrderEnabled(true)
和实现了父控件的getChildDrawingOrder()
方法, 那么顺序就是由这个方法里的实现确定了, 例如在这个方法传入参数是0的时候返回的是A的index, 传入1的时候返回的是B的index, 即使实际上A的index比B大, 那么事件也会先传递给A🎜如果你什么都没干, 就是正常使用, 那么分发顺序就是子控件在xml中的顺序的倒序, 就是后添加的先分发, 实际上如果两个控件重合了, 你看到的也是后添加的控件, 那么自然点击事件也是先分发给后添加的控件了
大致是这样, 有错欢迎指正.
我觉得是随机的(猜测),这种问题,你可以打个log或debug看下就知道了啊、
按你的描述,是上面那个先获得触摸事件,如果上面的那个不处理就会传给下面的viewgroup