谈谈|谈谈 android 事件分发机制--标准答案
最详细的讲解:
https://www.jianshu.com/p/38015afcdb58/
当被问到这个问题时,如何简洁并完整的回答这个问题?
现在一般会给个场景
- A 嵌套 B ,B 嵌套 C,从 C 中心按下,一下滑出到 A,描述事件分发的过程(包含ACTION_CANCEL 的调用时机)
通过打印日志来说明:https://www.jianshu.com/p/66a80ff0133b - ACTION_CANCEL怎么产生的
view消费了down事件,viewgroup在onInterceptTouchEvent中对于move事件返回true,在viewgroup的dispatch中就将被拦截的事件设置成cancel事件,发给view。简单地说有两个前提,子控件已经消费了 DOWN 事件,但父控件拦截了之后的事件 - B,C都设置onClick,在C按下,移动到B抬起,谁的onClick会响应?
如果是onClick事件,都不会响应,原因是,move事件会取消PFLAG_PRESSED的按下状态,按下移动再抬起就不会触发 click 事件。 - 一个 view 不消费ACTION_DOWN, 如何实现不再接受后续事件?
这个行为在官网上叫做 事件流一致性保证(Consistency Guarantees),在 ViewGroup.dispatchTouchEvent中,通过一个 TouchTarget 记录消费了 down 事件的 view,后续的事件序列只传给它,这个 TouchTarget 是一个链表,可以记录多点触控的多个目标,每一个ViewGroup都有一个TouchTarget - 滑动冲突处理:
(1)外部拦截方法 (在父容器的 onInterceptTouchEvent 进行控制,是否分发到子元素),遵循Android规范
(2)内部拦截方法(在子元素通过控制父容器的 requestDisallowInterceptTouchEvent 进行控制)
事件分发的的本质是将Touch事件 MotionEvent 传递到某个具体的View,以及处理事件的过程。
MotionEvent按照从Activity到ViewGroup再到View的顺序传递。
由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三个方法协作完成。
1.Activity
MotionEvent由WMS分发给应用程序后,从Activity.dispatchTouchEvent()开始,调用super.dispatchTouchEvent(),调用window.superDispatchTouchEvent(),再调用DecorView.superDispatchTouchEvent(),事件就传递到DecorView。
MotionEvent通过在DecorView中调用ViewGroup.dispatchTouchEven传递到它所持有的ViewGroup,如果Activity中super.dispatchTouchEvent返回的是false,那么会执行Activity.onTouchEvent(),并将onTouchEvent结果返回。
如果Activity中super.dispatchTouchEvent()返回为true,表示事件被子View消费,不执行Activity.OnTouchEvent().如果Activity不调用super.dispatchTouchEvent,那么事件就不会往子View传递。
2.ViewGroup
MotionEvent从ViewGroup.dispatchTouchEvent()开始传递,先通过ViewGroup.onInterceptTouchEvent()
判断是否需要拦截事件。
【谈谈|谈谈 android 事件分发机制--标准答案】这里有两个分支,如果onInterceptTouchEvent返回为false,则事件向子View传递,通过遍历找到被点击的子View,调用子View的dispatchTouchEvent, 并将结果返回。
如果onInterceptTouchEvent为true或者点击范围不在任何一个子View中(点击空白),则会调用父类View.dispatchTouchEvent, 再执行ViewGroup作为View的onTouch,onTouchEvent,performClick,onClick。
3.View
MotionEvent从View.dispatchTouchEvent开始传递。
如果onTouchListener不为空,调用onTouchListener.onTouch(),如果onTouch返回true,事件被消费,结果向Activity回溯,不再调用onClick()。
如果onTouch返回false,则会调用自身onTouchEvent(),onTouchEvent再调用performClick。在调用onClickListener.onClick(),dispatchTouchEvent返回true,结果向Activity回溯
推荐阅读
- android第三方框架(五)ButterKnife
- Android中的AES加密-下
- 事件代理
- 带有Hilt的Android上的依赖注入
- 事件处理程序
- android|android studio中ndk的使用
- 我在一条路上走了5年
- Android事件传递源码分析
- RxJava|RxJava 在Android项目中的使用(一)
- Android7.0|Android7.0 第三方应用无法访问私有库