android控件的事件传播机制

事件相关的三个事件方法
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;


@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
String msg = "MyView1 -> dispatchTouchEvent";
Log.d(TAG, msg);
return super.dispatchTouchEvent(ev);
}

@Override
public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值