Android成长之路-事件消费

一、Android事件构成
Android中用户操作事件比较多,包括点击、长按、移动、拖拽等,还分单手指多手指操作等,这些都构成了Android的事件响应。所有的操作事件都由三个基础部分组成:ACTION_DOWN,ACTION_MOVE,ACTION_UP。所有的操作事件必须先执行ACTION_DOWN,以此次ACTION_DOWN为前提分析接下来的用户行为,可能是ACTION_MOVE或者是ACTION_UP, ACTION_UP是操作事件的结束,这就是一组连续的Touch操作。所有的Touch事件都是用户通过操作屏幕引起的,而展现在屏幕上可与用户交互的正是Activity及各种View,所有的事件都是在Activity和该区域内的视图之间传递和响应的。


Activity视图层级

这是Activity响应事件的层级结构,与Touch事件相关方法有三个:dispatchTouchEvent(MotionEvent ev),onInterceptTouchEvent(MotionEvent ev)和onTouchEvent(MotionEvent ev)。dispatchTouchEvent方法用于事件的分发, 所有Android操作事件必须经过此方法来分发,然后决定是自己消费掉还是继续往下分发。onInterceptTouchEvent方法负责事件的拦截,如果拦截则不继续往下分发,否则继续分发。onTouchEvent方法负责事件的处理,它决定是否消费掉此事件。从上图可以看到,最外层的是Activity,不支持事件拦截,内层是视图容器ViewGroup,三个方法都支持,最内层的是View,由于它已经是最小的View单元,它没有子View,所有不支持事件分发和事件拦截,只有事件响应。

二、事件传递及消费
事件分发:public boolean dispatchTouchEvent(MotionEvent ev)
Activity接收到Touch事件时,Activity的dispatchTouchEvent方法将事件传递给最外层View的dispatchTouchEvent方法,再由该View对事件继续分发。此方法返回boolean值,如果为true,则此事件会被当前View的dispatchTouchEvent方法消费掉,事件停止往下传递。如果为false,则事件会返回给它的上一层对象的onTouchEvent方法消费掉。如果返回super.dispatchTouchEvent(ev),事件会自动的分发给当前View的onInterceptTouchEvent方法。

事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev)
此方法返回boolean值,表示是否对事件进行拦截。
如果为true,则表示将事件进行拦截,事件由当前View的onTouchEvent方法处理。如果为false,则表示不拦截,继续向下传递给子View,由子View执行dispatchTouchEvent分发。如果返回super.onInterceptTouchEvent(ev),事件不被拦截。

事件响应:public boolean onTouchEvent(MotionEvent ev)
此方法也返回boolean值,表示是否响应该事件。
如果为true,表示接收并消费掉事件。如果为false,那么此事件会从当前View向上传递,由上层View的onTouchEvent接收,如果继续返回false,那么事件就会舍弃,而且接收不到下一次事件。如果返回 super.onTouchEvent(ev)和false逻辑相同。具体逻辑可归结如下图:


这里写图片描述

所有的操作事件都是以ACTION_DOWN开始,以ACTION_UP结束的,UP的分发取决于DOWN是否分发。

三、实例验证
如果Activity、ViewGroup和View都没有重写这三个方法,也就是View和ViewGroup都没有对ACTION_DOWN事件进行消费,之后的其他事件(MOVE和UP等)也就不会传递下去了,只会在Activity层分发和处理。见Log:

05-15 12:43:40.210: D/Activity(8409): Activity---dispatchTouchEvent: DOWN
05-15 12:43:40.210: D/ViewGroup(8409): ViewGroup---dispatchTouchEvent: DOWN
05-15 12:43:40.210: D/View(8409): View---dispatchTouchEvent: DOWN
05-15 12:43:40.210: D/View(8409): View---onTouchEvent: DOWN
05-15 12:43:40.210: D/ViewGroup(8409): ViewGroup---onTouchEvent: DOWN
05-15 12:43:40.210: D/Activity(8409): Activity---onTouchEvent: DOWN
05-15 12:43:40.240: D/Activity(8409): Activity---dispatchTouchEvent: UP
05-15 12:43:40.240: D/Activity(8409): Activity---onTouchEvent: UP

如果我们在Activity的dispatchTouchEvent()方法中将ACTION_DOWN返回true,其他ACTION返回super.dispatchTouchEvent。也就是取消事件DOWN,那么Down事件会在Activity层取消,内层的ViewGroup和View接收不到DOWN事件,当然也接收不到其他事件。在Activity层DOWN事件被dispatchTouchEvent消费掉,其他事件就交给Activity的onTouchEvent消费。见Log:

05-15 13:02:02.670: D/Activity(9924): Activity---dispatchTouchEvent: DOWN
05-15 13:02:02.690: D/Activity(9924): Activity---dispatchTouchEvent: MOVE
05-15 13:02:02.690: D/Activity(9924): Activity---onTouchEvent: MOVE
05-15 13:02:02.710: D/Activity(9924): Activity---dispatchTouchEvent: MOVE
05-15 13:02:02.710: D/Activity(9924): Activity---onTouchEvent: MOVE
05-15 13:02:02.730: D/Activity(9924): Activity---dispatchTouchEvent: MOVE
05-15 13:02:02.730: D/Activity(9924): Activity---onTouchEvent: MOVE
05-15 13:02:02.730: D/Activity(9924): Activity---dispatchTouchEvent: UP
05-15 13:02:02.730: D/Activity(9924): Activity---onTouchEvent: UP

如果Down事件在ViewGroup层的dispatchTouchEvent()方法返回true,也即取消事件停止分发,那么后续的Move事件、Up事件也只能到达ViewGroup层,并在ViewGroup层取消分发。见Log:

05-15 13:15:12.700: D/Activity(10468): Activity---dispatchTouchEvent: DOWN
05-15 13:15:12.700: D/ViewGroup(10468): ViewGroup---dispatchTouchEvent: DOWN
05-15 13:15:12.720: D/Activity(10468): Activity---dispatchTouchEvent: MOVE
05-15 13:15:12.720: D/ViewGroup(10468): ViewGroup---dispatchTouchEvent: MOVE
05-15 13:15:12.730: D/Activity(10468): Activity---dispatchTouchEvent: UP
05-15 13:15:12.730: D/ViewGroup(10468): ViewGroup---dispatchTouchEvent: UP

如果在ViewGroup层拦截事件DOWN,那么后续的Move事件、Up事件都不会被下发。如果DOWN事件在ViewGroup消费掉了,那么Move事件、Up事件也会交给ViewGroup的onTouchEvent处理,如果DOWN事件没有被ViewGroup消费,那么Move事件、Up事件就不会下发给ViewGroup。见Log:

05-15 13:41:16.395: D/Activity(14166): Activity---dispatchTouchEvent: DOWN
05-15 13:41:16.395: D/ViewGroup(14166): ViewGroup---dispatchTouchEvent: DOWN
05-15 13:41:16.395: D/ViewGroup(14166): ViewGroup---onInterceptTouchEvent: DOWN, return true.
05-15 13:41:16.395: D/ViewGroup(14166): ViewGroup---onTouchEvent: DOWN, return false.
05-15 13:41:16.395: D/Activity(14166): Activity---onTouchEvent: DOWN
05-15 13:41:16.435: D/Activity(14166): Activity---dispatchTouchEvent: MOVE
05-15 13:41:16.435: D/Activity(14166): Activity---onTouchEvent: MOVE
05-15 13:41:16.455: D/Activity(14166): Activity---dispatchTouchEvent: MOVE
05-15 13:41:16.455: D/Activity(14166): Activity---onTouchEvent: MOVE
05-15 13:41:16.455: D/Activity(14166): Activity---dispatchTouchEvent: UP
05-15 13:41:16.455: D/Activity(14166): Activity---onTouchEvent: UP

如果DOWN事件分发到最内层的View,并且被View消费,即onTouchEvent返回true,那么MOVE和UP事件也会下发给View,是否消费就由View自己决定,如果不消费则向上传递。

05-15 14:04:08.095: D/Activity(14579): Activity---dispatchTouchEvent: DOWN
05-15 14:04:08.095: D/ViewGroup(14579): ViewGroup---dispatchTouchEvent: DOWN
05-15 14:04:08.095: D/View(14579): View---dispatchTouchEvent: DOWN
05-15 14:04:08.095: D/View(14579): View---onTouchEvent: DOWN, return true。
05-15 14:04:08.135: D/Activity(14579): Activity---dispatchTouchEvent: UP
05-15 14:04:08.135: D/ViewGroup(14579): ViewGroup---dispatchTouchEvent: UP
05-15 14:04:08.135: D/View(14579): View---dispatchTouchEvent: UP
05-15 14:04:08.135: D/View(14579): View---onTouchEvent: UP, return true。

四、总结
事件分发按照从外到内进行层级传递,Activity – ViewGroup – View
事件消费按照从内到外进行层级上传,如果onTouchEvent返回true,则事件在该层消费掉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值