Android布局中同级节点的触摸事件传递顺序
伊谢尔伦
伊谢尔伦 2017-04-17 17:41:57
0
3
441

一般的触摸事件传递顺序是ViewGroupRoot -> ViewGroupA -> View这样的。现在如果ViewGroupRoot下有两个同级的ViewGroupA和ViewGroupB,且两者宽高均为match_parent,那么请问这时的触摸事件传递顺序是怎样的?ViewGroupA和ViewGroupB谁先收到触摸事件?

伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

reply all(3)
刘奇

When logging or debugging, I just know the result but don’t know why. I will briefly analyze the logic that determines the delivery order.
The logic of the delivery order of touch events should be in the parent control’s dispatchTouchEvent() In the code> method, different parent controls may have different methods. If the implementation of this method of the parent control changes, the order may change. However, it generally will not change, so we only look at ViewGroup implementation, look at the source code, it is easy to find the part of the code that passes the touch event to the child control. The basic variable naming appears in the child pile. The key logic should be the following lines dispatchTouchEvent()方法中, 不同的父控件这个方法有可能不一样, 如果父控件的这个方法的实现改变了, 有可能会改变这个顺序.不过一般不会改的, 所以我们只看ViewGroup的实现, 看源码, 很容易找到把触摸事件传递给子控件的那部分代码, 基本变量命名出现child那堆就是了, 关键的逻辑应该是下面几行

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, 这个就是事件将要传递的子控件, 当然后面还要经过一些判断才会把事件分发给它, 不过这里不关心了.

决定这个child的实例的逻辑是final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex);,
关键的参数有两个, preorderedListchildIndex, 到这里基本可以确定触摸事件的分发顺序就是这两个参数决定的了.

接着看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, 它们大小相同, 位置重合

  1. 如果你对A或B设置了elevation或者translationZ, 那么会先分发给Z轴上值较大的View, 不设置的View默认是0, 此时index只能是xml上添加的顺序

  2. 如果你没有设置Z轴的值, 设置了setChildrenDrawingOrderEnabled(true)和实现了父控件的getChildDrawingOrder() rrreee

    Here you can clearly see that a variable final View child is defined. This is the child control to which the event will be passed. Of course, some judgments will be made later before the event will be distributed to it, but here I don’t care anymore. #🎜🎜# #🎜🎜#The logic that determines the instance of this child is final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex);, #🎜🎜#There are two key parameters, preorderedList and childIndex. At this point, you can basically determine that the order of distribution of touch events is determined by these two parameters.#🎜 🎜# #🎜🎜# Next, look at preorderedList, which calls the method buildOrderedChildList(). The code of this method will not be posted. If you do not set elevation or translationZ on the child control , then it will return empty. If it is set, it will return a list sorted according to the Z axis. Generally, it is not set. If you set the value of the Z axis, then The larger the value on the Z axis, the more priority events are distributed.#🎜🎜# #🎜🎜#Then look at childIndex. Generally, this value is the order defined in the xml file, but we can use the methods getChildDrawingOrder() and setChildrenDrawingOrderEnabled( boolean enabled) to customize the drawing order of child controls. If you set setChildrenDrawingOrderEnabled(true) then isChildrenDrawingOrderEnabled() will return true, causing the customOrder variable to be true when preorderedList is null, and then will be called getChildDrawingOrder() method to get the index of the child control dispatched by the current event.#🎜🎜# #🎜🎜#To summarize, the area you clicked has two Views, A and B. They are the same size and overlap in position#🎜🎜#
    1. #🎜🎜#If you set elevation or translationZ for A or B, it will be distributed to the View with the larger value on the Z axis first. The default value for the View that is not set is 0. At this time, the index can only be added to xml. The order of #🎜🎜#
    2. #🎜🎜#If you do not set the value of the Z axis, set setChildrenDrawingOrderEnabled(true) and implement the getChildDrawingOrder() method of the parent control, then the order is It is determined by the implementation in this method. For example, when the incoming parameter of this method is 0, the index of A is returned, and when 1 is passed in, the index of B is returned. Even if the index of A is actually larger than B, then The event will also be passed to A#🎜🎜# first
    3. If you do nothing and just use it normally, then the distribution order is the order of the sub-controls in the xml reverse order, that is, the ones added last are distributed first. In fact If the two controls overlap and what you see is the control added later, then the natural click event will be distributed to the control added later

    It’s roughly like this, please correct me if I’m wrong.

巴扎黑

I think it’s random (guess). For this kind of problem, you can log or debug it and you’ll know.

巴扎黑

According to your description, the one above gets the touch event first. If the one above does not handle it, it will be passed to the viewgroup below

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template