首页 > 系统 > Android > 正文

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

2019-11-09 18:14:57
字体:
来源:转载
供稿:网友

首先我们的实例布局结构如下: 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: 002-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 002-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 002-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 002-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyView: dispatchTouchEvent: 002-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyView: onTouchEvent: 002-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 002-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: 002-05 19:09:48.220 16493-16493/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 002-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: 002-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 002-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 002-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 002-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 002-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: 002-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 002-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 002-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 002-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyView: dispatchTouchEvent: 002-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: 002-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 002-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 002-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 002-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyView: dispatchTouchEvent: 002-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyView: onTouchEvent: 002-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 0

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

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表