在Android的事件处理过程中,经常会遇到需要拦截事件或者手动分发事件的情况,所以简单的了解一下Android的事件分发处理机制还是很有必要的。接下来, 借助一个简单的UI布局说明一下android的事件分发处理的工作流程!!
UI的简单的布局如图:
其中HELLO这个button为我们自定义的Button1,蓝色背景的布局为我们自定义的Group2,红色的为Group1。布局的xml如下所示:
<?xml version="1.0" encoding="utf-8"?>
<camera2.android.com.clickevent.Group1 xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent">
<camera2.android.com.clickevent.Group2
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@color/colorPrimaryDark">
<camera2.android.com.clickevent.Button1
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello" />
</camera2.android.com.clickevent.Group2>
</camera2.android.com.clickevent.Group1>
现在开始测试:
首先点击最外层的布局——Group1,打印的Log如下所示:
08-27 06:37:41.143 5428-5428/camera2.android.com.clickevent I/zyq: Group1-------onInterceptTouchEvent=false
08-27 06:37:41.143 5428-5428/camera2.android.com.clickevent I/zyq: Group1-------onTouchEvent=false
08-27 06:37:41.143 5428-5428/camera2.android.com.clickevent I/zyq: Group1-------dispatchTouchEvent=false
从log中可以看出,当我们点击一个view的时候,点击事件的分发和处理涉及到这三个方法:onInterceptTouchEvent、onTouchEvent、dispatchTouchEvent。
如果没有特殊的情况,这三个方法一般都是会走到的,而且在一个view中,当点击事件发生后,方法的执行顺序为:
onInterceptTouchEvent —>onTouchEvent—>dispatchTouchEvent
现在点击group2,打印的log如下:
08-27 06:37:56.085 5428-5428/camera2.android.com.clickevent I/zyq: Group1-------onInterceptTouchEvent=false
08-27 06:37:56.085 5428-5428/camera2.android.com.clickevent I/zyq: Group2-------onInterceptTouchEvent=false
08-27 06:37:56.085 5428-5428/camera2.android.com.clickevent I/zyq: Group2-------onTouchEvent=false
08-27 06:37:56.085 5428-5428/camera2.android.com.clickevent I/zyq: Group2-------dispatchTouchEvent=false
08-27 06:37:56.085 5428-5428/camera2.android.com.clickevent I/zyq: Group1-------onTouchEvent=false
08-27 06:37:56.085 5428-5428/camera2.android.com.clickevent I/zyq: Group1-------dispatchTouchEvent=false
根据log可以看出,首先捕捉到点击事件发生的View是最外层的UI,所以Group1有权决定是否将此次的点击事件中断,如果中断,将直接有Group1的onTouchEvent方法处理此次的点击事件,通过dispatchTouchEvent方发返回此次事件是否被消耗或者是否被分发成功等。
方法的执行流程为:
group1.onInterceptTouch—>group2.onInterceptTouch—>group2.onTouchEvent—>group2.dispatchTouchEvent—>group1.onTouchEvent—>group1.dispatchTouchEvent.
这是在事件没有任何处理的情况下会执行的流程,一旦事件被处理或者在onTouchEvent或者dispatchTouchEvent方法中返回true,那么都会表示这个事件已经被消耗,其外层的View将不会执行onTouchEvent方法,而是直接通过dispatchTouchEvent方法返回true,告诉其他相对外层的View事件已经被消耗!!
点击Button1,打印log如下:
ACTION_DOWN
08-27 06:38:51.301 5579-5579/camera2.android.com.clickevent I/zyq: Group1-------onInterceptTouchEvent=false
08-27 06:38:51.301 5579-5579/camera2.android.com.clickevent I/zyq: Group2-------onInterceptTouchEvent=false
08-27 06:38:51.303 5579-5579/camera2.android.com.clickevent I/zyq: Button1------onTouchEvent = true
08-27 06:38:51.303 5579-5579/camera2.android.com.clickevent I/zyq: Button1------dispatchTouchEvent = true
08-27 06:38:51.303 5579-5579/camera2.android.com.clickevent I/zyq: Group2-------dispatchTouchEvent=true
08-27 06:38:51.304 5579-5579/camera2.android.com.clickevent I/zyq: Group1-------dispatchTouchEvent=true
ACTION_UP
08-27 06:38:51.432 5579-5579/camera2.android.com.clickevent I/zyq: Group1-------onInterceptTouchEvent=false
08-27 06:38:51.432 5579-5579/camera2.android.com.clickevent I/zyq: Group2-------onInterceptTouchEvent=false
08-27 06:38:51.433 5579-5579/camera2.android.com.clickevent I/zyq: Button1------onTouchEvent = true
08-27 06:38:51.433 5579-5579/camera2.android.com.clickevent I/zyq: Button1------dispatchTouchEvent = true
08-27 06:38:51.433 5579-5579/camera2.android.com.clickevent I/zyq: Group2-------dispatchTouchEvent=true
08-27 06:38:51.433 5579-5579/camera2.android.com.clickevent I/zyq: Group1-------dispatchTouchEvent=true
点击了一下按钮,会执行两遍,这个就不多说了,看一下流程,基本与前面类似,但是由于Button1是继承至Button,可以有效的消耗用户的点击事件,所以group2和group1的onTouchEvent方法都没有执行,只是通过dispatchTouchEvent向相对外层的View说明事件的是否被消耗。
如果我们想要使得所有button点击事件都有Group2处理,不论group2能否正确处理都不能够将事件重新返回给Group1处理的话,我们可以选择使用事件拦截,首先在group2的onInterceptEvent方法中返回true,使得Group2拦截group2容器中的view点击事件,可以在group2的onTouchEvent或者dispatchTouchEvent方法中返回true,使其通知group1,这个事件已经被消耗,不需要group1在进行处理。
在没有事件拦截的情况下,最先执行的onTouchEvent方法的View肯定是用户点击的那个view。
关于Android的事件分发处理流程就说到这里,有兴趣的可以关注我一下,有什么问题可以相互讨论一下,谢谢!!