Android控件架构与自定义控件详解(四)事件拦截机制分析

首先我们的实例布局结构如下:
MyViewGroupA——最外层的ViewGroup
MyViewGroupB——中间的ViewGroup
MyView——最底层的View
这里写图片描述

代码非常简单只是重写了事件拦截和处理的几个方法,并给它加上一些Log而已

对于ViewGroup来说,重写了如下三个方法

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i(TAG, "dispatchTouchEvent: " + ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i(TAG, "onInterceptTouchEvent: " + ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: " + event.getAction());
        return super.onTouchEvent(event);
    }

而对于View来说,重写了如下两个方法

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i(TAG, "dispatchTouchEvent: " + event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i(TAG, "onTouchEvent: " + event.getAction());
        return super.onTouchEvent(event);
    }

ViewGroup级别比较高,比View多了一个方法——onInterceptTouchEvent()方法

首先我们不修改任何返回值,仅仅点击一下MyView,Log如下所示:

02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyView: dispatchTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyView: onTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupA: onTouchEvent: 0

可以看见,正常情况下,事件的传递顺序是:
MyViewGroupA->MyViewGroupB->MyView。事件传递的时候,执行dispatchTouchEvent()方法,再执行onInterceptTouchEvent()方法。

事件的处理顺序是:
MyView->MyViewGroupB->MyViewGroupA。事件处理都是执行onTouchEvent()方法。

事件传递的返回值非常容易理解:true,拦截,不继续;false,不拦截,继续流程。

事件处理的返回值也类似:true,处理了,不用审核了;false, 给父ViewGroup处理。

初始情况下,返回值都是false。

这里为了能够方便大家理解事件拦截的过程,在事件传递中,我们只关心onInterceptTouchEvent()方法,而dispatchTouchEvent()方法虽然是事件分发的第一步,但一般情况下,我们不太会去改写这个方法

这里让MyViewGroupA把事件拦截了,即让MyViewGroupA的onInterceptTouchEvent()方法返回true,Log如下:

02-05 19:09:48.220 16493-16493/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 19:09:48.220 16493-16493/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 19:09:48.220 16493-16493/com.example.customviewlayout I/MyViewGroupA: onTouchEvent: 0

MyViewGroupA把事件拦截了,因此MyViewGroupB和MyView都接收不到事件了

下面让MyViewGroupB把事件拦截了,即让MyViewGroupB的onInterceptTouchEvent()方法返回true,Log如下:

02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupA: onTouchEvent: 0

MyViewGroupB把事件拦截了,因此MyView接收不到事件了

在事件的处理中,事件分发到MyView然后它处理完事件,需要向父布局报告,所以MyView的事件处理返回false,但若MyView的onTouchEvent()方法返回true时,Log日志如下:

02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyView: dispatchTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyView: onTouchEvent: 0

可以看见,事件传递和以前一样,但是事件处理,到MyView这里就结束了,因为MyView返回true,表示不用向父布局汇报了。
注:设为false时只能监听到值为0的down事件,设为true时就能监听到值为1或2的move up等等其它事件

如果MyView返回了false,MyViewGroupB想拦截这个事件,于是将onTouchEvent()方法返回true,那整个事件也就到此为止了,Log如下:

02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyView: dispatchTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyView: onTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 0

注:在ViewGroup中设为true时同样就能监听到值为1或2的move up等等其它事件

通过以上几种情况相信大家能比较容易的了解事件的分发、拦截、处理事件的流程了。

代码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值