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

本文通过一个实例详细解析了Android中事件拦截机制的工作流程。从ViewGroup到View层面,介绍了dispatchTouchEvent、onInterceptTouchEvent及onTouchEvent等关键方法的作用及其执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了能够方便地了解事件拦截机制的整个流程,设计这样一个实例:

  1. MyViewGroupA——最外层的ViewGroup
  2. MyViewGroupB——中间的ViewGroup
  3. MyView——最底层的View

效果图如下:

这里写图片描述

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

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

    /**
     * 该方法虽然是事件分发的第一步,但一般情况下,我们不太会去改写这个方法
     * @param ev
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d("xys", "ViewGroupA dispatchTouchEvent" + ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 事件拦截的核心方法
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.d("xys", "ViewGroupA onInterceptTouchEvent" + ev.getAction());
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("xys", "ViewGroupA onTouchEvent" + event.getAction());
        return super.onTouchEvent(event);
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d("xys", "View onTouchEvent" + event.getAction());
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d("xys", "View dispatchTouchEvent" + event.getAction());
        return super.dispatchTouchEvent(event);
    }

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

(一)
我们先不修改任何返回值,运行程序后,点击一下MyView,Log日记记录如下:

05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: View dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: View onTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB onTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA onTouchEvent0

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

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

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

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

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

(二)
如果我们让MyViewGroupA把事件拦截了,即让MyViewGroupA的onInterceptTouchEvent()方法返回true,Log日志如下:

05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA onTouchEvent0

MyViewGroupA把所有的事都干了,也就没有后面的人的事了。

(三)
再比如我们让MyViewGroupB把事件拦截了,即让MyViewGroupB的onInterceptTouchEvent()方法返回true,Log日志如下:

05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB onTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA onTouchEvent0

MyViewGroupB把事情干了,MyView就不用干活了。

(四)
在事件的处理中,最开始时MyView把事情干完了,需要向父布局报告,所以MyView的事件处理返回false,但若MyView的onTouchEvent()方法返回true,再看看Log日志:

05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: View dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: View onTouchEvent0

看以看到,事件传递和以前一样,但是事件处理,到MyView这就结束了,因为MyView返回true,表示不用向父布局汇报了。

(五)
若MyViewGroupB的onTouchEvent()方法返回true,整个事件也就到此为止了,Log日志如下:

05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupA onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB onInterceptTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: View dispatchTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: View onTouchEvent0
05-15 19:15:24.730 31442-31442/com.imooc.viewlayout D/xys: ViewGroupB onTouchEvent0

代码地址

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值