android控件的事件传播机制

来源:互联网 发布:华为云计算认证招聘 编辑:程序博客网 时间:2024/05/05 04:53

事件相关的三个事件方法
dispatcherEvent 负责分发事件的, 函数主要作用是来决定当前的事件是交由自己消费处理,还是交由子控件处理。
返回true,表示事件不再向下分发,事件在这次分发中消费掉。
返回false表示该组件不参与事件分发,事件交由上层组件的onTouchEvent处理。
返回值为super.dispatcherEvent时,表示事件将向下分发。

onInterceptTouchEvent   决定是否要拦截这个事件。    返回true,则事件不再向下传递,交由组件的onTouchEvent处理。    返回false,则事件继续向下传递。onTouchEvent 决定事件是否继续向上冒泡。        返回true则事件不再向上冒泡,事件被直接消费掉。        返回false则事件向上冒泡。

调用顺序

 dispatcherEvent   ->        onInterceptTouchEvent    - > onTouchEvent 

下面用一实例来证明上面的结论。
我写了三个简单的控件继承已有的控件,并实现其中事件响应的方法。

public class MyViewGroup1 extends RelativeLayout{     //...省略构造方法@Override public boolean onTouchEvent(MotionEvent event) {  String msg = "MyViewGroup1 -> onTouchEvent";  Log.d(TAG, msg);  return super.onTouchEvent(event); } /**  * 返回false 拦截事件 返回true 放  */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  String msg = "MyViewGroup1 -> onInterceptTouchEvent";  Log.d(TAG, msg);  return super.onInterceptTouchEvent(ev); } @Override public boolean dispatchTouchEvent(MotionEvent ev) {  isFirst = false;  String msg = "MyViewGroup1 -> dispatchTouchEvent";  Log.d(TAG, msg);  return super.dispatchTouchEvent(ev); } }}
-------public class MyViewGroup2 extends RelativeLayout{ //...省略构```/**  * 返回false 拦截事件  * 返回true 放  */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) {  String msg = "MyViewGroup2 -> onInterceptTouchEvent";  Log.d(TAG, msg);  return super.onInterceptTouchEvent(ev); } @Override public boolean dispatchTouchEvent(MotionEvent ev) {  String msg = "MyViewGroup2 -> dispatchTouchEvent";  Log.d(TAG, msg);  return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) {  String msg = "MyViewGroup2 -> onTouchEvent";  Log.d(TAG, msg);  return super.dispatchTouchEvent(ev); } }}--------------public class MyView1 extends TextView {private static final String TAG = "MyViewGroup2";private boolean isFirst = true;@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {String msg = "MyView1 -> dispatchTouchEvent";Log.d(TAG, msg);return super.dispatchTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {if (isFirst) {isFirst = false;String msg = "MyView1 -> onTouchEvent";Log.d(TAG, msg);return super.dispatchTouchEvent(ev);} else {return true;}}}//为了让防止点击时响应多次点击,加入以上代码中的isFirst判断----------------------------------------
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <wei.jiang.selfview.eventtest.MyViewGroup1        android:id="@+id/outGroup"        android:layout_width="match_parent"        android:layout_height="match_parent" >        <wei.jiang.selfview.eventtest.MyViewGroup2            android:id="@+id/inGroup"            android:layout_centerInParent="true"            android:background="@android:color/darker_gray"            android:layout_width="200px"            android:layout_height="200px" >            <wei.jiang.selfview.eventtest.MyView1                android:id="@+id/content"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:gravity="center"                android:layout_centerInParent="true"                android:text="内容" >            </wei.jiang.selfview.eventtest.MyView1>        </wei.jiang.selfview.eventtest.MyViewGroup2>    </wei.jiang.selfview.eventtest.MyViewGroup1></LinearLayout>

这里写图片描述
这是我们画出的组件,其中文字部分是MyView1, 灰色部分是MyViewGroup2, 白色部分是MyViewGroup1,
我们在不修改任务事件方法的情况下,日志如下。
这里写图片描述
图1

可以看出只有最里层的子控件响应了onTouchEvent.

首先来实验dispatchTouch方法,这里我们改改MyViewGroup2即中间控件组的dispatchTouch方法的返回值,结果如下:        return true ->             

这里写图片描述 图2
可以 看到事件到了viewGroup2的dispatchTouchEvent方法时就直接被消耗掉。

    return false ->

这里写图片描述 图3
事件又返回到上层父控件的onTouchEvent的方法响应。这里父控件响应了这次的touch事件,并。

这里可以得到结论。
dispatchTouchEvent
返回true,表示事件不再向下分发,事件在这次分发中消费掉。
返回false表示该组件不参与事件分发,事件交由上层组件的onTouchEvent处理。
返回值为super.dispatcherEvent时,表示事件将向下分发。

现在来看onInterceptTouchEvent, 查看父类源码可发现父类直接返回了false,所以这里修改成true看结果。
return true ->这里写图片描述
图4
这里可以看出事件都是在viewGroup2的onTouchEvent中被响应,但事件并没有被消耗掉,事件会不断的在MyViewGroup2中传递。

最后我们来修改onTouchEvent的返回值,
return true -> 这里写图片描述
图5
可以看出事件到了MyViewGroup2被正常消耗掉。事件被拦截了一次
return false -> 这里写图片描述

                                                                                       图6                    事件被MyViewGroup2响应,并且冒泡给了MyViewGroup2的onTouchEvent方法响应。

做到这里,上面的关于三个事件分发方法的结论已经得到了验证。但还有一个问题就是事件的消耗的问题,
做到这里,上面的关于三个事件分发方法的结论已经得到了验证。但还有一个问题就是事件的消耗的问题,
1. 当dispatchTouch方法返回true或者onTouchEvent方法返回true时 如图2,事件被耗掉,日志中会有两次响应的过程,
但只有第一次响应了onInterceptTouchEvent方法,如图5,查看源码可以发现onInterceptTouchEvent对拦截做过判断,
说明这是两次事件过程,个人理解是按下与松开的事件。

    2.  当事件返回到上层父控件响应后,事件响应过程只有一次,如图3,6, 说明事件被冒泡到上层后被上层消耗掉,之后相同事件将会直接被上层响应。(侍论证)    3,当事件没有被消耗掉时,如图4,事件会在子控件中不断的响应,这里应该是由onTouchEvent方法内部不断的循环调用造成。
1 0
原创粉丝点击