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

    xiaoxiao2021-03-26  21

    首先我们的实例布局结构如下: 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等等其它事件

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

    代码下载

    转载请注明原文地址: https://ju.6miu.com/read-661954.html

    最新回复(0)