上一篇博客我介绍了在学习事件分发机制过程中遇到的一个问题,接下来的几篇博客将通过小Demo来测试下事件分发机制,进而能更好的理解源码,至于源码的分析,网上有很多帖子了,大家可以自行查看啦!
注意本篇博客是默认在你理解了ViewGroup和View事件分发源码的基础上讲解的,请先了解源码之后再来照着里面的测试进行理解!!
点击下载测试代码!!!!!
下面的所有测试代码都是在上面链接代码的基础上修改的,好了,我们开始吧!
我们采用的布局文件:
<com.hzw.eventtest.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.hzw.eventtest.MyLinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.hzw.eventtest.MyButton android:id="@+id/mybutton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我的按钮" /> </com.hzw.eventtest.MyLinearLayout> </com.hzw.eventtest.MyRelativeLayout>
也即布局文件图是酱紫的:
测试1:(默认处理方式)
也就是我们不对整个分发过程进行任何人为干预处理,不对上面的测试代码进行修改;
点击MyButton按钮之后查看Logcat输出:
06-28 21:26:54.537: I/System.out(941): MainActivity--->dispatchTouchEvent--->ACTION_DOWN 06-28 21:26:54.537: I/System.out(941): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN 06-28 21:26:54.537: I/System.out(941): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-28 21:26:54.537: I/System.out(941): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-28 21:26:54.537: I/System.out(941): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN 06-28 21:26:54.537: I/System.out(941): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-28 21:26:54.547: I/System.out(941): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-28 21:26:54.547: I/System.out(941): MyButton--->dispatchTouchEvent--->ACTION_DOWN 06-28 21:26:54.547: I/System.out(941): MyButton--->onTouchEvent--->ACTION_DOWN 06-28 21:26:54.567: I/System.out(941): MyButton--->onTouchEvent--->ACTION_DOWN--->true 06-28 21:26:54.567: I/System.out(941): MyButton--->dispatchTouchEvent--->ACTION_DOWN--->true 06-28 21:26:54.577: I/System.out(941): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN--->true 06-28 21:26:54.577: I/System.out(941): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN--->true 06-28 21:26:54.577: I/System.out(941): MainActivity--->dispatchTouchEvent--->ACTION_DOWN--->true 06-28 21:26:54.577: I/System.out(941): MainActivity--->dispatchTouchEvent--->ACTION_MOVE 06-28 21:26:54.577: I/System.out(941): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE 06-28 21:26:54.577: I/System.out(941): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE 06-28 21:26:54.588: I/System.out(941): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE--->false 06-28 21:26:54.588: I/System.out(941): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE 06-28 21:26:54.588: I/System.out(941): MyLinearLayout--->onInterceptTouchEvent--->ACTION_MOVE 06-28 21:26:54.588: I/System.out(941): MyLinearLayout--->onInterceptTouchEvent--->ACTION_MOVE--->false 06-28 21:26:54.588: I/System.out(941): MyButton--->dispatchTouchEvent--->ACTION_MOVE 06-28 21:26:54.598: I/System.out(941): MyButton--->onTouchEvent--->ACTION_MOVE 06-28 21:26:54.598: I/System.out(941): MyButton--->onTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.598: I/System.out(941): MyButton--->dispatchTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.598: I/System.out(941): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.598: I/System.out(941): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.598: I/System.out(941): MainActivity--->dispatchTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.639: I/System.out(941): MainActivity--->dispatchTouchEvent--->ACTION_MOVE 06-28 21:26:54.639: I/System.out(941): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE 06-28 21:26:54.657: I/System.out(941): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE 06-28 21:26:54.657: I/System.out(941): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE--->false 06-28 21:26:54.668: I/System.out(941): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE 06-28 21:26:54.668: I/System.out(941): MyLinearLayout--->onInterceptTouchEvent--->ACTION_MOVE 06-28 21:26:54.668: I/System.out(941): MyLinearLayout--->onInterceptTouchEvent--->ACTION_MOVE--->false 06-28 21:26:54.668: I/System.out(941): MyButton--->dispatchTouchEvent--->ACTION_MOVE 06-28 21:26:54.668: I/System.out(941): MyButton--->onTouchEvent--->ACTION_MOVE 06-28 21:26:54.668: I/System.out(941): MyButton--->onTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.668: I/System.out(941): MyButton--->dispatchTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.668: I/System.out(941): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.668: I/System.out(941): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.668: I/System.out(941): MainActivity--->dispatchTouchEvent--->ACTION_MOVE--->true 06-28 21:26:54.677: I/System.out(941): MainActivity--->dispatchTouchEvent--->ACTION_UP 06-28 21:26:54.677: I/System.out(941): MyRelativeLayout--->dispatchTouchEvent--->ACTION_UP 06-28 21:26:54.677: I/System.out(941): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP 06-28 21:26:54.677: I/System.out(941): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP--->false 06-28 21:26:54.677: I/System.out(941): MyLinearLayout--->dispatchTouchEvent--->ACTION_UP 06-28 21:26:54.677: I/System.out(941): MyLinearLayout--->onInterceptTouchEvent--->ACTION_UP 06-28 21:26:54.677: I/System.out(941): MyLinearLayout--->onInterceptTouchEvent--->ACTION_UP--->false 06-28 21:26:54.677: I/System.out(941): MyButton--->dispatchTouchEvent--->ACTION_UP 06-28 21:26:54.677: I/System.out(941): MyButton--->onTouchEvent--->ACTION_UP 06-28 21:26:54.687: I/System.out(941): MyButton--->onTouchEvent--->ACTION_UP--->true 06-28 21:26:54.687: I/System.out(941): MyButton--->dispatchTouchEvent--->ACTION_UP--->true 06-28 21:26:54.687: I/System.out(941): MyLinearLayout--->dispatchTouchEvent--->ACTION_UP--->true 06-28 21:26:54.687: I/System.out(941): MyRelativeLayout--->dispatchTouchEvent--->ACTION_UP--->true 06-28 21:26:54.687: I/System.out(941): MainActivity--->dispatchTouchEvent--->ACTION_UP--->true
先来看看DOWN事件:
分发首先从MainActivity开始,执行他的dispatchTouchEvent方法,这个方法最终会通过DecorView里面的superDispatchTouchEvent来调用ViewGroup的dispatchTouchEvent方法,而这个方法呢就开始整个View树的分发过程了,首先分发到MyRelativeLayout上面,调用它的dispatchTouchEvent方法,接着调用它的onInterceptTouchEvent方法来查看是否拦截DOWN事件,这里是默认情况,所以返回false不拦截,接着继续分发到MyLinearLayout上面,调用它的dispatchTouchEvent,因为MyLinearLayout也是ViewGroup,所以会调用它的onInterceptTouchEvent来进行判断是否拦截的判断,这里仍然默认,所以返回false,接着事件分发到了MyButton上面,他是一个View所以没有onInterceptEvent事件拦截方法,因为我们没有为他设置Touch事件监听器,所以直接执行他的onTouchEvent方法,这个方法的默认返回值是true,因而DOWN事件在MyButton中被消费了,接下来的第11--14行输出就是递归的返回过程了,因为事件已经得到消费,所以不再会执行MyLinearLayout、MyRelativeLayout、MainActivity的onTouchEvent方法了;
接下来的MOVE和UP事件的分发过程和DOWN事件是一致的,输出也是一样的,需要注意的是第17和20行为什么还是会执行MyRelativeLayout和MyLinearLayout的onInterceptTouchEvent方法呢?这个需要查看下ViewGroup的源码了,源码在我的上篇博客有贴出来,在ViewGroup$dispatchTouchEvent源码的第23行if语句中mFirstTouchTarget是不为null的,所以它会执行里面的第27行onInterceptTouchEvent方法,具体来说这里的mFirstTouchTarget其实就是封装有MyButton的TouchTarget对象啦!
测试2:(默认处理方式)
同样我们也不对链接中的测试代码进行任何修改;
但是这次我们点击的是除MyButton之外的空白部分,查看Logcat输出:
06-29 00:09:56.982: I/System.out(1343): MainActivity--->dispatchTouchEvent--->ACTION_DOWN 06-29 00:09:56.988: I/System.out(1343): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN 06-29 00:09:56.988: I/System.out(1343): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-29 00:09:56.988: I/System.out(1343): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-29 00:09:56.997: I/System.out(1343): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN 06-29 00:09:56.997: I/System.out(1343): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-29 00:09:56.997: I/System.out(1343): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-29 00:09:57.007: I/System.out(1343): MyLinearLayout--->onTouchEvent--->ACTION_DOWN 06-29 00:09:57.007: I/System.out(1343): MyLinearLayout--->onTouchEvent--->ACTION_DOWN--->false 06-29 00:09:57.007: I/System.out(1343): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN--->false 06-29 00:09:57.007: I/System.out(1343): MyRelativeLayout--->onTouchEvent--->ACTION_DOWN 06-29 00:09:57.007: I/System.out(1343): MyRelativeLayout--->onTouchEvent--->ACTION_DOWN--->false 06-29 00:09:57.018: I/System.out(1343): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN--->false 06-29 00:09:57.018: I/System.out(1343): MainActivity--->onTouchEvent--->ACTION_DOWN 06-29 00:09:57.018: I/System.out(1343): MainActivity--->onTouchEvent--->ACTION_DOWN--->false 06-29 00:09:57.018: I/System.out(1343): MainActivity--->dispatchTouchEvent--->ACTION_DOWN--->false 06-29 00:09:57.098: I/System.out(1343): MainActivity--->dispatchTouchEvent--->ACTION_MOVE 06-29 00:09:57.098: I/System.out(1343): MainActivity--->onTouchEvent--->ACTION_MOVE 06-29 00:09:57.098: I/System.out(1343): MainActivity--->onTouchEvent--->ACTION_MOVE--->false 06-29 00:09:57.098: I/System.out(1343): MainActivity--->dispatchTouchEvent--->ACTION_MOVE--->false 06-29 00:09:57.107: I/System.out(1343): MainActivity--->dispatchTouchEvent--->ACTION_UP 06-29 00:09:57.107: I/System.out(1343): MainActivity--->onTouchEvent--->ACTION_UP 06-29 00:09:57.107: I/System.out(1343): MainActivity--->onTouchEvent--->ACTION_UP--->false 06-29 00:09:57.107: I/System.out(1343): MainActivity--->dispatchTouchEvent--->ACTION_UP--->false可以看到1--7行的输出和测试1是一样的,第8行开始进入的是MyLinearLayout的onTouchEvent方法,这个是什么原因呢?原因在于我们点击的区域并不包含有MyButton,那么事件就不会传递到他了,虽然我们在MyLinearLayout中没有拦截DOWN方法,但是仍然会执行他的onTouchEvent方法,查看ViewGroup$dispatchEvent源码(见上篇博客)的第71行if语句中的isTransformedTouchPointInView方法,我们这里点击的是MyButton以外的部分,那么该方法的返回值将是false满足if语句判断条件,结束本次循环,又因为MyLinearLayout之后不存在别的子View了,所以执行第111行代码进行判断查看mFirstTouchTarget的值,当事件由ViewGroup的子元素成功处理时,mFirstTouchTarget才会被赋值指向子元素,因为现在DOWN事件没有被任何View处理,那么mFirstTouchTarget的值将是null,满足第111行的if判断语句,执行112行代码,具体就会执行MyLinearLayout的onTouchEvent方法;了,因为MyLinearLayout并没有消费DOWN事件,那么他会传递给MyRelativeLayout来进行处理,所以出现了第11行的输出,调用了MyRelativeLayout的onTouchEvent方法,又因为他也没有消费DOWN事件,那么将事件传递给了MainActivity,调用他的onTouchEvent方法,所以有了第14行的输出,从第17行开始是对DOWN和UP事件的处理,可以看到此后的事件不再会传递到MainActivity的子View了,都是由MainActivity进行处理的,原因就在于仍然是查看上篇博客的ViewGroup$dispatchEvent源码,在DOWN事件处理结束之后,MOVE事件还是首先分发到MainActivity上面,执行他的dispatchTouchEvent方法,也就是ViewGroup的dispatchTouchEvent方法了,在该方法中mFirstTouchTarget是为null的,因为DOWN事件并不是由MainActivity的子View处理的,只有被MainActivity的子View处理了mFirstTouchTarget才不为null,所以也就执行的是dispatchTouchEvent源码的第112行代码了,和上面一样会执行super.dispatchTouchEvent了,也就是View的dispatchTouchEvent了,在这个方法里面会执行MainActivity的onTouchEvent方法的,所以有了MianActivity直接来处理MOVE和UP事件的情况,不再将事件分发下去;
测试3:(MyLinearLayout仅拦截DOWN事件,但是不消费该事件)
也就是我们仅仅修改MyLinearLayout$onInterceptTouchEvent方法的case条件值为DOWN语句部分,让他的result=true即可;
点击MyButton按钮之后查看Logcat输出:
06-28 23:34:51.499: I/System.out(1203): MainActivity--->dispatchTouchEvent--->ACTION_DOWN 06-28 23:34:51.499: I/System.out(1203): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN 06-28 23:34:51.508: I/System.out(1203): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-28 23:34:51.508: I/System.out(1203): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-28 23:34:51.508: I/System.out(1203): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN 06-28 23:34:51.508: I/System.out(1203): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-28 23:34:51.508: I/System.out(1203): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN--->true 06-28 23:34:51.517: I/System.out(1203): MyLinearLayout--->onTouchEvent--->ACTION_DOWN 06-28 23:34:51.517: I/System.out(1203): MyLinearLayout--->onTouchEvent--->ACTION_DOWN--->false 06-28 23:34:51.517: I/System.out(1203): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN--->false 06-28 23:34:51.517: I/System.out(1203): MyRelativeLayout--->onTouchEvent--->ACTION_DOWN 06-28 23:34:51.517: I/System.out(1203): MyRelativeLayout--->onTouchEvent--->ACTION_DOWN--->false 06-28 23:34:51.517: I/System.out(1203): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN--->false 06-28 23:34:51.517: I/System.out(1203): MainActivity--->onTouchEvent--->ACTION_DOWN 06-28 23:34:51.517: I/System.out(1203): MainActivity--->onTouchEvent--->ACTION_DOWN--->false 06-28 23:34:51.527: I/System.out(1203): MainActivity--->dispatchTouchEvent--->ACTION_DOWN--->false 06-28 23:34:51.669: I/System.out(1203): MainActivity--->dispatchTouchEvent--->ACTION_MOVE 06-28 23:34:51.669: I/System.out(1203): MainActivity--->onTouchEvent--->ACTION_MOVE 06-28 23:34:51.669: I/System.out(1203): MainActivity--->onTouchEvent--->ACTION_MOVE--->false 06-28 23:34:51.669: I/System.out(1203): MainActivity--->dispatchTouchEvent--->ACTION_MOVE--->false 06-28 23:34:51.677: I/System.out(1203): MainActivity--->dispatchTouchEvent--->ACTION_MOVE 06-28 23:34:51.677: I/System.out(1203): MainActivity--->onTouchEvent--->ACTION_MOVE 06-28 23:34:51.677: I/System.out(1203): MainActivity--->onTouchEvent--->ACTION_MOVE--->false 06-28 23:34:51.677: I/System.out(1203): MainActivity--->dispatchTouchEvent--->ACTION_MOVE--->false 06-28 23:34:51.748: I/System.out(1203): MainActivity--->dispatchTouchEvent--->ACTION_UP 06-28 23:34:51.748: I/System.out(1203): MainActivity--->onTouchEvent--->ACTION_UP 06-28 23:34:51.748: I/System.out(1203): MainActivity--->onTouchEvent--->ACTION_UP--->false 06-28 23:34:51.748: I/System.out(1203): MainActivity--->dispatchTouchEvent--->ACTION_UP--->false输出中的第1--6行和测试1的结果一样,我们直接从第7行开始分析,因为我们在MyLinearLayout中拦截了DOWN事件,所以onInterceptTouchEvent方法的返回值是true,接下来就是执行MyLinearLayout的onTouchEvent方法了,因为我们在MyLinearLayout中并没有消费该事件,所以onTouchEvent方法返回false,相应的该事件将会交给MyLinearLayout的上一级MyRelativeLayout来处理了,所以第11行输出调用了MyRelativeLayout的onTouchEvent方法,同样我们没有在MyRelativeLayout中消费DOWN事件,那么onTouchEvent返回false,接下来该事件会交给MyRelativeLayout的上一级MainActivity来处理了,调用他的onTouchEvent方法,所以第14行输出调用了MainActivity的onTouchEvent方法,接下来MainActivity的disPathchTouchEvent返回false,那么到这里DOWN事件分发就结束了,MainActivity处理了DOWN事件;接下来就是MOVE事件的分发了,刚开始当然是调用MainActivity的dispatchTouchEvent了,因为DOWN事件是MainActivity处理的,所以接下来的MOVE和UP事件不会向下分发了,直接调用MainActivity的onTouchEvent进行处理啦!
测试4:(MyLinearLayout仅消费DOWN事件,但是不拦截DOWN事件)
也就是仅修改MyLinearLayout的onTouchEvent方法的case条件为DOWN的部分,将此条件下的result值修改为true;
点击MyButton查看Logcat输出:
06-29 03:05:34.841: I/System.out(1406): MainActivity--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:05:34.841: I/System.out(1406): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:05:34.841: I/System.out(1406): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-29 03:05:34.848: I/System.out(1406): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-29 03:05:34.848: I/System.out(1406): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:05:34.848: I/System.out(1406): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-29 03:05:34.848: I/System.out(1406): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-29 03:05:34.848: I/System.out(1406): MyButton--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:05:34.858: I/System.out(1406): MyButton--->onTouchEvent--->ACTION_DOWN 06-29 03:05:34.858: I/System.out(1406): MyButton--->onTouchEvent--->ACTION_DOWN--->true 06-29 03:05:34.858: I/System.out(1406): MyButton--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:05:34.858: I/System.out(1406): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:05:34.858: I/System.out(1406): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:05:34.858: I/System.out(1406): MainActivity--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:05:34.947: I/System.out(1406): MainActivity--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:05:34.947: I/System.out(1406): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:05:34.947: I/System.out(1406): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE 06-29 03:05:34.947: I/System.out(1406): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE--->false 06-29 03:05:34.947: I/System.out(1406): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:05:34.947: I/System.out(1406): MyLinearLayout--->onInterceptTouchEvent--->ACTION_MOVE 06-29 03:05:34.947: I/System.out(1406): MyLinearLayout--->onInterceptTouchEvent--->ACTION_MOVE--->false 06-29 03:05:34.947: I/System.out(1406): MyButton--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:05:34.947: I/System.out(1406): MyButton--->onTouchEvent--->ACTION_MOVE 06-29 03:05:34.947: I/System.out(1406): MyButton--->onTouchEvent--->ACTION_MOVE--->true 06-29 03:05:34.947: I/System.out(1406): MyButton--->dispatchTouchEvent--->ACTION_MOVE--->true 06-29 03:05:34.957: I/System.out(1406): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE--->true 06-29 03:05:34.957: I/System.out(1406): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE--->true 06-29 03:05:34.957: I/System.out(1406): MainActivity--->dispatchTouchEvent--->ACTION_MOVE--->true 06-29 03:05:34.957: I/System.out(1406): MainActivity--->dispatchTouchEvent--->ACTION_UP 06-29 03:05:34.957: I/System.out(1406): MyRelativeLayout--->dispatchTouchEvent--->ACTION_UP 06-29 03:05:34.957: I/System.out(1406): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP 06-29 03:05:34.957: I/System.out(1406): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP--->false 06-29 03:05:34.968: I/System.out(1406): MyLinearLayout--->dispatchTouchEvent--->ACTION_UP 06-29 03:05:34.968: I/System.out(1406): MyLinearLayout--->onInterceptTouchEvent--->ACTION_UP 06-29 03:05:34.968: I/System.out(1406): MyLinearLayout--->onInterceptTouchEvent--->ACTION_UP--->false 06-29 03:05:34.968: I/System.out(1406): MyButton--->dispatchTouchEvent--->ACTION_UP 06-29 03:05:34.968: I/System.out(1406): MyButton--->onTouchEvent--->ACTION_UP 06-29 03:05:34.968: I/System.out(1406): MyButton--->onTouchEvent--->ACTION_UP--->true 06-29 03:05:34.968: I/System.out(1406): MyButton--->dispatchTouchEvent--->ACTION_UP--->true 06-29 03:05:34.968: I/System.out(1406): MyLinearLayout--->dispatchTouchEvent--->ACTION_UP--->true 06-29 03:05:34.968: I/System.out(1406): MyRelativeLayout--->dispatchTouchEvent--->ACTION_UP--->true 06-29 03:05:34.968: I/System.out(1406): MainActivity--->dispatchTouchEvent--->ACTION_UP--->true你会发现这个测试的Logcat输出和测试1的输出是一模一样的,原因在于,我们在MyLinearLayout仅仅是消费了DOWN事件,但是没有拦截他,那么该事件还是会分发到MyButton上面的,而MyButton作为View,在执行他的onTouchEvent方法的时候默认是消费DOWN事件的,也就是说DOWN事件在MyButton已经被消费了,所以11--14行只是递归的退出过程,并没有执行MyLinearLayout、MyRelativeLayout、MainActivity的任何方法的,以后的MOVE事件和UP事件处理方法和DOWN事件是一致的;
测试5:(那么我们在测试4的基础上修改MyButton的onTouchEvent方法case条件为DOWN部分,让他返回false看看会有什么情况发生吧)
也就是我们这里是在链接测试代码的基础上修改了MyLinearLayout的onTouchEvent方法的case条件为DOWN的部分,将此条件下的result值修改为true;同时修改MyButton的onTouchEvent方法case条件为DOWN部分,让他返回false;
点击MyButton查看Logcat输出:
06-29 03:24:15.534: I/System.out(1450): MainActivity--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:24:15.537: I/System.out(1450): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:24:15.537: I/System.out(1450): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-29 03:24:15.537: I/System.out(1450): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-29 03:24:15.537: I/System.out(1450): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:24:15.547: I/System.out(1450): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-29 03:24:15.547: I/System.out(1450): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-29 03:24:15.557: I/System.out(1450): MyButton--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:24:15.557: I/System.out(1450): MyButton--->onTouchEvent--->ACTION_DOWN 06-29 03:24:15.557: I/System.out(1450): MyButton--->onTouchEvent--->ACTION_DOWN--->false 06-29 03:24:15.557: I/System.out(1450): MyButton--->dispatchTouchEvent--->ACTION_DOWN--->false 06-29 03:24:15.577: I/System.out(1450): MyLinearLayout--->onTouchEvent--->ACTION_DOWN 06-29 03:24:15.577: I/System.out(1450): MyLinearLayout--->onTouchEvent--->ACTION_DOWN--->true 06-29 03:24:15.577: I/System.out(1450): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:24:15.577: I/System.out(1450): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:24:15.577: I/System.out(1450): MainActivity--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:24:15.650: I/System.out(1450): MainActivity--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:24:15.650: I/System.out(1450): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:24:15.650: I/System.out(1450): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE 06-29 03:24:15.657: I/System.out(1450): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE--->false 06-29 03:24:15.657: I/System.out(1450): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:24:15.657: I/System.out(1450): MyLinearLayout--->onTouchEvent--->ACTION_MOVE 06-29 03:24:15.657: I/System.out(1450): MyLinearLayout--->onTouchEvent--->ACTION_MOVE--->false 06-29 03:24:15.657: I/System.out(1450): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE--->false 06-29 03:24:15.657: I/System.out(1450): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE--->false 06-29 03:24:15.657: I/System.out(1450): MainActivity--->onTouchEvent--->ACTION_MOVE 06-29 03:24:15.657: I/System.out(1450): MainActivity--->onTouchEvent--->ACTION_MOVE--->false 06-29 03:24:15.657: I/System.out(1450): MainActivity--->dispatchTouchEvent--->ACTION_MOVE--->false 06-29 03:24:15.657: I/System.out(1450): MainActivity--->dispatchTouchEvent--->ACTION_UP 06-29 03:24:15.667: I/System.out(1450): MyRelativeLayout--->dispatchTouchEvent--->ACTION_UP 06-29 03:24:15.667: I/System.out(1450): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP 06-29 03:24:15.667: I/System.out(1450): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP--->false 06-29 03:24:15.667: I/System.out(1450): MyLinearLayout--->dispatchTouchEvent--->ACTION_UP 06-29 03:24:15.667: I/System.out(1450): MyLinearLayout--->onTouchEvent--->ACTION_UP 06-29 03:24:15.667: I/System.out(1450): MyLinearLayout--->onTouchEvent--->ACTION_UP--->false 06-29 03:24:15.667: I/System.out(1450): MyLinearLayout--->dispatchTouchEvent--->ACTION_UP--->false 06-29 03:24:15.667: I/System.out(1450): MyRelativeLayout--->dispatchTouchEvent--->ACTION_UP--->false 06-29 03:24:15.667: I/System.out(1450): MainActivity--->onTouchEvent--->ACTION_UP 06-29 03:24:15.667: I/System.out(1450): MainActivity--->onTouchEvent--->ACTION_UP--->false 06-29 03:24:15.667: I/System.out(1450): MainActivity--->dispatchTouchEvent--->ACTION_UP--->false没错,我相信这样的输出结果一定会让你大跌眼镜,1--9行和测试4的输出一致,第10行发现MyButton的onTouchEvent的返回是false,也就是他没有消费了DOWN事件,那么他会将DOWN事件传递给他的上一级也就是MyRelativeLayout了,执行他的onTouchEvent方法,因为我们在MyRelativeLayout中消费了DOWN事件,所以第13行返回了true,接下来的14--16行就是递归的退出过程了,实质上没有执行任何方法的;继续查看对于MOVE事件的输出,刚开始的17--21行的分发过程是正常过程,发现第22行直接就去执行MyLinearLayout的onTouchEvent方法了,原因在于分发到MyLinearLayout的时候,mFirstTouchTarget(当事件由ViewGroup的子元素成功处理时,mFirstTouchTarget会被赋值指向子元素,因为上面的DOWN事件是由MyLinearLayout处理的,不是他的子元素,所以mFirstTouchTarget的值是等于null的,这也就解释了为什么MyRelativeLayout会执行onInterceptTouchEvent而MyLinearLayout不会执行onInterceptTouchEvent,如果你对这里不太明白,建议你还是先去看看ViewGroup$dispatchTouchEvent源码部分mFirstTouchTarget的作用到底是什么吧),因为我们没有在MyLinearLayout中消费MOVE事件,所以第23行onTouchEvent方法返回的是false,接下来就只好把MOVE事件传递给MainActivity来处理了,很多人在想,为什么不把时间传递给MyRelativeLayout来处理呢?原因在于在事件分发机制中有一个用来存储可以处理DOWN事件的链表,如果某个View可以处理DOWN事件的话那么会将该View加入到这个链表中,从上面的DOWN事件处理过程中发现MyLinearLayout将事件消费掉之后,MyRelativeLayout不可能有资格处理DOWN事件的,所以他不会在这个链表中,那么MOVE事件就只能给MainActivity处理了,他就像是一个母亲一样,儿子们解决不了的问题最后都无条件的交给她来处理了;随后的MOVE事件以及UP事件的处理过程就和第一次的MOVE事件处理过程一样啦!
测试6:(MyLinearLayout既拦截DOWN事件,同时也消费DOWN事件)
也就是我们修改MyLinearLayout$onInterceptTouchEvent方法的case条件值为DOWN语句部分,让他的result=true,同时修改MyLinearLayout的onTouchEvent方法的case条件为DOWN的部分,将此条件下的result值修改为true;
点击MyButton查看Logcat输出:
06-29 03:52:57.487: I/System.out(1508): MainActivity--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:52:57.487: I/System.out(1508): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:52:57.487: I/System.out(1508): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-29 03:52:57.487: I/System.out(1508): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_DOWN--->false 06-29 03:52:57.497: I/System.out(1508): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN 06-29 03:52:57.497: I/System.out(1508): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN 06-29 03:52:57.507: I/System.out(1508): MyLinearLayout--->onInterceptTouchEvent--->ACTION_DOWN--->true 06-29 03:52:57.507: I/System.out(1508): MyLinearLayout--->onTouchEvent--->ACTION_DOWN 06-29 03:52:57.507: I/System.out(1508): MyLinearLayout--->onTouchEvent--->ACTION_DOWN--->true 06-29 03:52:57.507: I/System.out(1508): MyLinearLayout--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:52:57.507: I/System.out(1508): MyRelativeLayout--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:52:57.507: I/System.out(1508): MainActivity--->dispatchTouchEvent--->ACTION_DOWN--->true 06-29 03:52:57.593: I/System.out(1508): MainActivity--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:52:57.593: I/System.out(1508): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:52:57.598: I/System.out(1508): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE 06-29 03:52:57.598: I/System.out(1508): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_MOVE--->false 06-29 03:52:57.598: I/System.out(1508): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE 06-29 03:52:57.598: I/System.out(1508): MyLinearLayout--->onTouchEvent--->ACTION_MOVE 06-29 03:52:57.598: I/System.out(1508): MyLinearLayout--->onTouchEvent--->ACTION_MOVE--->false 06-29 03:52:57.598: I/System.out(1508): MyLinearLayout--->dispatchTouchEvent--->ACTION_MOVE--->false 06-29 03:52:57.598: I/System.out(1508): MyRelativeLayout--->dispatchTouchEvent--->ACTION_MOVE--->false 06-29 03:52:57.598: I/System.out(1508): MainActivity--->onTouchEvent--->ACTION_MOVE 06-29 03:52:57.598: I/System.out(1508): MainActivity--->onTouchEvent--->ACTION_MOVE--->false 06-29 03:52:57.598: I/System.out(1508): MainActivity--->dispatchTouchEvent--->ACTION_MOVE--->false 06-29 03:52:57.598: I/System.out(1508): MainActivity--->dispatchTouchEvent--->ACTION_UP 06-29 03:52:57.598: I/System.out(1508): MyRelativeLayout--->dispatchTouchEvent--->ACTION_UP 06-29 03:52:57.598: I/System.out(1508): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP 06-29 03:52:57.608: I/System.out(1508): MyRelativeLayout--->onInterceptTouchEvent--->ACTION_UP--->false 06-29 03:52:57.608: I/System.out(1508): MyLinearLayout--->dispatchTouchEvent--->ACTION_UP 06-29 03:52:57.608: I/System.out(1508): MyLinearLayout--->onTouchEvent--->ACTION_UP 06-29 03:52:57.608: I/System.out(1508): MyLinearLayout--->onTouchEvent--->ACTION_UP--->false 06-29 03:52:57.608: I/System.out(1508): MyLinearLayout--->dispatchTouchEvent--->ACTION_UP--->false 06-29 03:52:57.608: I/System.out(1508): MyRelativeLayout--->dispatchTouchEvent--->ACTION_UP--->false 06-29 03:52:57.608: I/System.out(1508): MainActivity--->onTouchEvent--->ACTION_UP 06-29 03:52:57.608: I/System.out(1508): MainActivity--->onTouchEvent--->ACTION_UP--->false 06-29 03:52:57.608: I/System.out(1508): MainActivity--->dispatchTouchEvent--->ACTION_UP--->false可以看出1--6行的输出和测试1是一样的,第7行因为我们在MyLinearLayout中拦截了DOWN事件,所以执行他的onInterceptTouchEvent方法时返回的是true,接下来就是执行他自身的onTouchEvent方法了,同样我们在MyLinearLayout中消费了DOWN事件,所以第9行MyLinearLayout的onTouchEvent方法返回true,这样的话DOWN事件处理结束,10--12行是递归退出过程,第13行开始进行MOVE事件的分发,首先当然是执行MainActivity的dispatchTouchEvent方法了,接着将其分发到了MyRelativeLayout上面,执行他的dispatchTouchEvent方法,也就是执行ViewGroup的dispatchTouchEvent方法了,这个方法中的mFirstTouchTarget不为null,所以会执行MyRelativeLayout的onInterceptTouchEvent方法,因为MyRelativeLayout没有拦截MOVE事件,因而该方法返回false,那么就将事件分发到了MyLinearLayout上面了,执行他的dispatchTouchEvent方法,此时这个方法里面的mFirstTouchTarget是等于null的,原因在于前面的DOWN事件是当前View执行的,所以不会执行他的onInterceptTouchEvent方法,同样因为mFirstTouchTarget为null,接下来就会执行MyLinearLayout的onTouchEvent方法,因为我们没有在MyLinearLayout中消费MOVE事件,那么该事件会进行回传,但是之前能处理DOWN事件的View只有MyLinearLayout,而此时他又没有消费MOVE事件,那么接下来只能交给MainActivity来处理了;之后的MOVE事件以及UP事件的处理过程和第一次MOVE的过程是一致;
从上面的6个测试代码我们可以得出以下结论:
(1)如果一个View没有处理过DOWN事件,即没有通过调用该View的onTouchEvent方法来处理DOWN事件,那么他就没有权利执行随后的MOVE以及UP事件,注意这里所说的View是包括ViewGroup的,并且这里所说的处理DOWN事件意思只是处理,没有说非要消费掉DOWN事件;
(2)如果一个View(当然这里指的是ViewGroup)的DOWN事件是由当前View自己处理的,那么接下来的MOVE或者UP事件如果能够传递到当前View的话,是不再会执行当前View的onInterceptTouchEvent方法的,直接会去执行他的onTouchEvent方法的;