简单版,没有精力完善更多的东西。
测试对象:
EventActivity:重写了dispatchTouchEvent和onTouchEvent
EventViewGroup1:重写了dispatchTouchEvent和onInterceptTouchEvent和onTouchEvent
EventViewGroup2:重写了dispatchTouchEvent和onInterceptTouchEvent和onTouchEvent
EventView:重写了dispatchTouchEvent和onTouchEvent
测试情况一:dispatchTouchEvent和onInterceptTouchEvent和onTouchEvent三个被重写的方法都返回super.xxx
输出结果为:
06-15 08:14:56.962 1695-1695/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:14:56.962 1695-1695/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 08:14:56.962 1695-1695/com.aprz.delak E/EventTest﹕ EventViewGroup1---onInterceptTouchEvent---
06-15 08:14:56.962 1695-1695/com.aprz.delak E/EventTest﹕ EventViewGroup2---dispatchTouchEvent---
06-15 08:14:56.962 1695-1695/com.aprz.delak E/EventTest﹕ EventViewGroup2---onInterceptTouchEvent---
06-15 08:14:56.962 1695-1695/com.aprz.delak E/EventTest﹕ EventView---dispatchTouchEvent---
06-15 08:14:56.963 1695-1695/com.aprz.delak E/EventTest﹕ EventView---onTouchEvent---
06-15 08:14:56.963 1695-1695/com.aprz.delak E/EventTest﹕ EventViewGroup2---onTouchEvent---
06-15 08:14:56.963 1695-1695/com.aprz.delak E/EventTest﹕ EventViewGroup1---onTouchEvent---
06-15 08:14:56.963 1695-1695/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
06-15 08:14:57.070 1695-1695/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:14:57.070 1695-1695/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
06-15 08:14:57.086 1695-1695/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:14:57.086 1695-1695/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
06-15 08:14:57.103 1695-1695/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:14:57.103 1695-1695/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
最后只打印EventActicity是因为:EventViewGroup1和EventViewGroup2和EventViewGroup1都不消费事件,所以本次的后续事件就不往下传递了,activity自己处理。
为了证明上面的结论,做这样一个测试,让EventViewGroup2来消费这次事件(在onTouchEvent里返回true),输出打印结果如下:
06-15 08:16:52.590 1800-1800/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:16:52.590 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 08:16:52.590 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---onInterceptTouchEvent---
06-15 08:16:52.590 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---dispatchTouchEvent---
06-15 08:16:52.590 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---onInterceptTouchEvent---
06-15 08:16:52.590 1800-1800/com.aprz.delak E/EventTest﹕ EventView---dispatchTouchEvent---
06-15 08:16:52.590 1800-1800/com.aprz.delak E/EventTest﹕ EventView---onTouchEvent---
06-15 08:16:52.590 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---onTouchEvent---
06-15 08:16:52.703 1800-1800/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:16:52.703 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 08:16:52.703 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---onInterceptTouchEvent---
06-15 08:16:52.703 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---dispatchTouchEvent---
06-15 08:16:52.703 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---onTouchEvent---
06-15 08:16:52.720 1800-1800/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:16:52.720 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 08:16:52.721 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---onInterceptTouchEvent---
06-15 08:16:52.721 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---dispatchTouchEvent---
06-15 08:16:52.721 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---onTouchEvent---
06-15 08:16:52.736 1800-1800/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:16:52.736 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 08:16:52.736 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---onInterceptTouchEvent---
06-15 08:16:52.736 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---dispatchTouchEvent---
06-15 08:16:52.736 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---onTouchEvent---
06-15 08:16:52.753 1800-1800/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:16:52.753 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 08:16:52.753 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---onInterceptTouchEvent---
06-15 08:16:52.753 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---dispatchTouchEvent---
06-15 08:16:52.753 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---onTouchEvent---
06-15 08:16:52.770 1800-1800/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 08:16:52.770 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 08:16:52.770 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup1---onInterceptTouchEvent---
06-15 08:16:52.770 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---dispatchTouchEvent---
06-15 08:16:52.770 1800-1800/com.aprz.delak E/EventTest﹕ EventViewGroup2---onTouchEvent---
可以看出后续的事件,每次传递到EventViewGroup2便不往下面传递了,这也正说明了:
dispatchTouchEvent()方法中有“记忆”的功能,如果第一次事件向下传递到某View,它把事件继续传递交给它的子View,它会记录该事件是否被它下面的View给处理成功了,(怎么能知道呢?如果该事件会再次被向上传递到我这里来由我的onTouchEvent()来处理,那就说明下面的View都没能成功处理该事件);当第二次事件向下传递到该View,该View的dispatchTouchEvent()方法机会判断,若上次的事件由下面的view成功处理了,那么这次的事件就继续交给下面的来处理,若上次的事件没有被下面的处理成功,那么这次的事件就不会向下传递了,该View直接调用自己的onTouchEvent()方法来处理该事件。
“记忆”功能的信息只在一系列事件完成之前有效,如从ACTION_DOWN事件开始,直到后续事件ACTION_MOVE,ACTION_UP结束后,“记忆”的信息就会清除。也就是说如果某View处理ACTION_DOWN事件失败了(onTouchEvent()返回false),那么后续的ACTION_MOVE,ACTION_UP等事件就不会再传递到该View了,由其父View自己来处理。在下一次发生ACTION_DOWN事件的时候,还是会传递到该View的。
测试情况二:看看EventViewGroup1的dispatchTouchEvent返回返回true,会发生什么?
06-15 07:11:02.797 2154-2154/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:11:02.797 2154-2154/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 07:11:02.938 2154-2154/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:11:02.938 2154-2154/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 07:11:02.952 2154-2154/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:11:02.952 2154-2154/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 07:11:02.968 2154-2154/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:11:02.969 2154-2154/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 07:11:02.984 2154-2154/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:11:02.985 2154-2154/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
可以看出,事件被EventViewGroup1的dispatchTouchEvent消费了。
测试情况三:看看EventViewGroup1的dispatchTouchEvent返回返回false,会发生什么?
06-15 07:16:51.100 2358-2358/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:16:51.100 2358-2358/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 07:16:51.100 2358-2358/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
06-15 07:16:51.168 2358-2358/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:16:51.168 2358-2358/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
06-15 07:16:51.184 2358-2358/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:16:51.184 2358-2358/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
06-15 07:16:51.201 2358-2358/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:16:51.201 2358-2358/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
事件被返回给上层来源了,让其onTouchEvent来处理。
测试情况四:看看EventViewGroup2的dispatchTouchEvent返回返回false,会发生什么?
06-15 07:20:03.892 2463-2463/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:20:03.892 2463-2463/com.aprz.delak E/EventTest﹕ EventViewGroup1---dispatchTouchEvent---
06-15 07:20:03.892 2463-2463/com.aprz.delak E/EventTest﹕ EventViewGroup1---onInterceptTouchEvent---
06-15 07:20:03.892 2463-2463/com.aprz.delak E/EventTest﹕ EventViewGroup2---dispatchTouchEvent---
06-15 07:20:03.892 2463-2463/com.aprz.delak E/EventTest﹕ EventViewGroup1---onTouchEvent---
06-15 07:20:03.892 2463-2463/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
06-15 07:20:04.002 2463-2463/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:20:04.002 2463-2463/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
06-15 07:20:04.018 2463-2463/com.aprz.delak E/EventTest﹕ EventActivity---dispatchTouchEvent---
06-15 07:20:04.019 2463-2463/com.aprz.delak E/EventTest﹕ EventActivity---onTouchEvent---
事件返回给上层去处理了,如果上层也不处理,继续向上返回,一直到activity,可以看出activity和ViewGroup是不一样的,就算不处理事件,仍然会接收到下次事件。
最终的结论如下:
▐ 事件分发:public boolean dispatchTouchEvent(MotionEvent ev)
Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:
- 如果 return true,事件会分发给当前 View 并由 dispatchTouchEvent 方法进行消费,同时事件会停止向下传递;
- 如果 return false,事件分发分为两种情况:
- 如果当前 View 获取的事件直接来自 Activity,则会将事件返回给 Activity 的 onTouchEvent 进行消费;
- 如果当前 View 获取的事件来自外层父控件,则会将事件返回给父 View 的 onTouchEvent 进行消费。
- 如果返回系统默认的 super.dispatchTouchEvent(ev),事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。
▐ 事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev)
在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下:
- 如果 onInterceptTouchEvent 返回 true,则表示将事件进行拦截,并将拦截到的事件交由当前 View 的 onTouchEvent 进行处理;
- 如果 onInterceptTouchEvent 返回 false,则表示将事件放行,当前 View 上的事件会被传递到子 View 上,再由子 View 的 dispatchTouchEvent 来开始这个事件的分发;
- 如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev),与返回false时相同。
▐ 事件响应:public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:
- 如果事件传递到当前 View 的 onTouchEvent 方法,而该方法返回了 false,那么这个事件会从当前 View 向上传递,并且都是由上层 View 的 onTouchEvent 来接收,如果传递到上面的 onTouchEvent 也返回 false,这个事件就会“消失”,而且接收不到下一次事件。
- 如果返回了 true 则会接收并消费该事件。
- 如果返回 super.onTouchEvent(ev) 默认处理事件的逻辑和返回 false 时相同。