最近在写一个自定义的ViewGroup,涉及到MotionEvent的分发。看了一些资料后发现还是有点迷迷糊糊的,所以动手写了Demo,打log来观察到底是怎么传递的。希望以下内容能帮到各位。
环境说明:
-
整个界面如下所示:
蓝框是 ViewGroup,红框是个宽高都是 MATCH_PARENT 的 View
蓝框是个继承于LinearLayout的自定义ViewGroup,类名为VGDemo,在onInterceptTouchEvent、dispatchTouchEvent和onTouchEvent中添加了打log的语句。
红框是个继承于View的自定义View,类名为VDemo,在dispatchTouchEvent和onTouchEvent中添加了打log的语句,它在蓝框之内,宽高都是MATCH_PARENT。 操作是,在红框范围内,单指,按下 → 滑动 → 抬起。
在情况分析中每一份logcat的输出都是在执行了上述操作后的输出,在每一次执行操作之前都有清空logcat的行为,为了不引入上一次的输出,以免妨碍观察。
情况分析与总结:
- 假设整个链路上所有自定义添加了打log的方法都是return false的话,整个流程是
dispatchTouchEvent(ViewGroup) → onInterceptTouchEvent(ViewGroup)
→ dispatchTouchEvent(View) → onTouchEvent(View)
→ onTouchEvent(ViewGroup)
此时意味着任何事件在整个链路上都没有被消费,自然也包括DOWN事件,那么这样只会有DOWN事件会传入这个链路,又因为DOWN事件没有被消费,那么接下来直到下一个DOWN事件之前的任何点击事件都不会被传入这个链路中。
logcat的输出为:
10-31 10:22:44.286 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_DOWN
10-31 10:22:44.286 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_DOWN
10-31 10:22:44.287 testapplication.view.VDemo: dispatchTouchEvent: ACTION_DOWN
10-31 10:22:44.287 testapplication.view.VDemo: onTouchEvent: ACTION_DOWN
10-31 10:22:44.288 testapplication.view.VGDemo: onTouchEvent: ACTION_DOWN
- 如果某个DOWN事件在最内层的onTouchEvent消费了,那么接下来直到下一个DOWN事件之前的任何点击事件,不管最内层的onTouchEvent还会不会消费它们,它们的终点都是这个最内层的onTouchEvent,不会传递到VG的onTouchEvent处。即此时的分发链路为:
dispatchTouchEvent(ViewGroup) → onInterceptTouchEvent(ViewGroup) → dispatchTouchEvent(View) → onTouchEvent(View)
在最内层的onTouchEvent中指定消费了DOWN事件后的logcat输出:
10-31 10:19:17.544 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_DOWN
10-31 10:19:17.544 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_DOWN
10-31 10:19:17.544 testapplication.view.VDemo: dispatchTouchEvent: ACTION_DOWN
10-31 10:19:17.544 testapplication.view.VDemo: onTouchEvent: ACTION_DOWN
10-31 10:19:17.569 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:19:17.569 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_MOVE
10-31 10:19:17.569 testapplication.view.VDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:19:17.569 testapplication.view.VDemo: onTouchEvent: ACTION_MOVE
10-31 10:19:17.723 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:19:17.724 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_MOVE
10-31 10:19:17.724 testapplication.view.VDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:19:17.724 testapplication.view.VDemo: onTouchEvent: ACTION_MOVE
....四条重复,循环
10-31 10:19:18.072 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:19:18.072 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_MOVE
10-31 10:19:18.072 testapplication.view.VDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:19:18.072 testapplication.view.VDemo: onTouchEvent: ACTION_MOVE
10-31 10:19:18.072 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_UP
10-31 10:19:18.072 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_UP
10-31 10:19:18.072 testapplication.view.VDemo: dispatchTouchEvent: ACTION_UP
10-31 10:19:18.072 testapplication.view.VDemo: onTouchEvent: ACTION_UP
- 在2的情形下,如果VG在onInterceptTouchEvent中对接下来直到下一个DOWN事件之前的任何一个点击事件进行拦截(即返回true),那么从拦截事件开始到下一个DOWN事件之前的任何点击事件都会走
dispatchTouchEvent(ViewGroup) → onTouchEvent(ViewGroup)
这个链路,不再经过其他流程;而拦截这个事件的同时,VG会分发个CANCEL的事件给原来消费了DOWN事件的子View。
指定对MOVE事件进行拦截时的logcat输出如下:
10-31 10:11:00.321 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_DOWN
10-31 10:11:00.321 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_DOWN
10-31 10:11:00.321 testapplication.view.VDemo: dispatchTouchEvent: ACTION_DOWN
10-31 10:11:00.321 testapplication.view.VDemo: onTouchEvent: ACTION_DOWN
10-31 10:11:00.340 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:11:00.340 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_MOVE
10-31 10:11:00.340 testapplication.view.VDemo: dispatchTouchEvent: ACTION_CANCEL
10-31 10:11:00.340 testapplication.view.VDemo: onTouchEvent: ACTION_CANCEL
10-31 10:11:00.357 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:11:00.357 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 10:11:00.374 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:11:00.374 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 10:11:00.391 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:11:00.391 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 10:11:00.409 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:11:00.409 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 10:11:00.426 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:11:00.426 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 10:11:00.444 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 10:11:00.444 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 10:11:00.743 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_UP
10-31 10:11:00.743 testapplication.view.VGDemo: onTouchEvent: ACTION_UP
- 在2的情形下,如果VG在dispatchTouchEvent中对接下来直到下一个DOWN事件之前的任何一个点击事件进行分发(即返回true),那么对于指定的分发事件,它们都会只经过dispatchTouchEvent(ViewGroup),不会经过其他事件(所以如果是要分发到VG的onTouchEvent,请务必要自行在dispatchTouchEvent那里调用onTouchEvent方法!),也不会通知子View一个CANCEL事件;而对于没有指定分发的事件,则是仍旧走2中的分发链路。
指定对MOVE事件进行分发时的logcat输出如下:
10-31 09:32:39.036 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_DOWN
10-31 09:32:39.036 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_DOWN
10-31 09:32:39.036 testapplication.view.VDemo: dispatchTouchEvent: ACTION_DOWN
10-31 09:32:39.037 testapplication.view.VDemo: onTouchEvent: ACTION_DOWN
10-31 09:32:39.049 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.084 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.104 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.122 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.139 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.157 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.174 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.192 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.209 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.226 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.245 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.261 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 09:32:39.488 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_UP
10-31 09:32:39.488 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_UP
10-31 09:32:39.488 testapplication.view.VDemo: dispatchTouchEvent: ACTION_UP
10-31 09:32:39.489 testapplication.view.VDemo: onTouchEvent: ACTION_UP
- 如果DOWN事件在VG的onTouchEvent中被消耗,那么接下来直到下一个DOWN事件之前的任何点击事件都是走
dispatchTouchEvent(ViewGroup) → onTouchEvent(ViewGroup)
这个链路,不会走到View里面的任何方法,也不会走到VG的onInterceptTouchEvent方法。
logcat输出为:
10-31 11:18:22.980 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_DOWN
10-31 11:18:22.980 testapplication.view.VGDemo: onInterceptTouchEvent: ACTION_DOWN
10-31 11:18:22.980 testapplication.view.VDemo: dispatchTouchEvent: ACTION_DOWN
10-31 11:18:22.980 testapplication.view.VDemo: onTouchEvent: ACTION_DOWN
10-31 11:18:22.980 testapplication.view.VGDemo: onTouchEvent: ACTION_DOWN
10-31 11:18:22.987 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:22.987 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.003 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.003 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.021 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.021 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.038 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.038 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.056 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.056 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.073 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.073 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.090 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.090 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.108 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.108 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.125 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.125 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.143 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.143 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.160 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.160 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.178 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.178 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.191 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_MOVE
10-31 11:18:23.191 testapplication.view.VGDemo: onTouchEvent: ACTION_MOVE
10-31 11:18:23.191 testapplication.view.VGDemo: dispatchTouchEvent: ACTION_UP
10-31 11:18:23.191 testapplication.view.VGDemo: onTouchEvent: ACTION_UP
参考资料: