谈谈 android 事件分发机制--标准答案

最详细的讲解:
https://www.jianshu.com/p/38015afcdb58/
当被问到这个问题时,如何简洁并完整的回答这个问题?

现在一般会给个场景

  1. A 嵌套 B ,B 嵌套 C,从 C 中心按下,一下滑出到 A,描述事件分发的过程(包含ACTION_CANCEL 的调用时机)
    通过打印日志来说明:https://www.jianshu.com/p/66a80ff0133b
  2. ACTION_CANCEL怎么产生的
    view消费了down事件,viewgroup在onInterceptTouchEvent中对于move事件返回true,在viewgroup的dispatch中就将被拦截的事件设置成cancel事件,发给view。简单地说有两个前提,子控件已经消费了 DOWN 事件,但父控件拦截了之后的事件
  3. B,C都设置onClick,在C按下,移动到B抬起,谁的onClick会响应?
    如果是onClick事件,都不会响应,原因是,move事件会取消PFLAG_PRESSED的按下状态,按下移动再抬起就不会触发 click 事件。
  4. 一个 view 不消费ACTION_DOWN, 如何实现不再接受后续事件?
    这个行为在官网上叫做 事件流一致性保证(Consistency Guarantees),在 ViewGroup.dispatchTouchEvent中,通过一个 TouchTarget 记录消费了 down 事件的 view,后续的事件序列只传给它,这个 TouchTarget 是一个链表,可以记录多点触控的多个目标,每一个ViewGroup都有一个TouchTarget
  5. 滑动冲突处理:
    (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()
判断是否需要拦截事件。

这里有两个分支,如果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 事件分发机制--标准答案)