Android开发中MotionEvent的传递 学习笔记

最近在写一个自定义的ViewGroup,涉及到MotionEvent的分发。看了一些资料后发现还是有点迷迷糊糊的,所以动手写了Demo,打log来观察到底是怎么传递的。希望以下内容能帮到各位。


环境说明:

  1. 整个界面如下所示:

    蓝框是 ViewGroup,红框是个宽高都是 MATCH_PARENT 的 View

    蓝框是个继承于LinearLayout的自定义ViewGroup,类名为VGDemo,在onInterceptTouchEvent、dispatchTouchEvent和onTouchEvent中添加了打log的语句。
    红框是个继承于View的自定义View,类名为VDemo,在dispatchTouchEvent和onTouchEvent中添加了打log的语句,它在蓝框之内,宽高都是MATCH_PARENT。

  2. 操作是,在红框范围内,单指,按下 → 滑动 → 抬起。

  3. 在情况分析中每一份logcat的输出都是在执行了上述操作后的输出,在每一次执行操作之前都有清空logcat的行为,为了不引入上一次的输出,以免妨碍观察。

情况分析与总结:

  1. 假设整个链路上所有自定义添加了打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
  1. 如果某个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
  1. 在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
  1. 在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
  1. 如果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

参考资料:

  1. 公共技术点之 View 事件传递 - @codeKK 开源站
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容