美文网首页Android自定义View
android 事件分发原理

android 事件分发原理

作者: 前行的乌龟 | 来源:发表于2018-06-06 15:48 被阅读230次

事件分发在 android 中实在是太重要了,滑动冲突的前置基础知识,滑动冲突不会处理,那么大部分页面效果是写不出来的,尤其是时下越来越多的联合滑动的页面效果,典型的就是 behavior 了,其他的像是典型的滑动控件嵌套冲突,左滑退出,列表侧滑菜单,下拉刷新,上拉加载都是需要我们对 android 事件分发有深刻理解的。

事件分发谁来控制

android 的页面结构是这样的,典型的树形结构


页面结构图1 页面结构图2

每一个 Actvity 都有一个 window ,window 所有视图的最顶层容器,视图的外观和行为都归他管,不论是背景显示,标题栏还是事件处理都是他管理。

一般我们用不到去操作 window ,但是触控事件的接收和分发是由 window 来执行的,window 会根据视图树的顺序,从外向里层层传递触控事件

所以触控事件是由 window 接收并分发的。

事件分发4大方法

  • dispatchTouchEvent 事件分发
  • onInterceptTouchEvent 事件拦截
  • onTouchEvent 事件处理
  • requestDisallowInterceptTouchEvent(true)

ViewGroup 4个方法都有,View 没有事件拦截方法。这4个方法就是 Android 事件分发和处理的具体方法了,我们在实际处理时都是重写这4个方法。

这3个方法都有一个 boolean 的返回值,onInterceptTouchEvent 方法表示我要拦截这个事件,onTouchEvent 表示我处理了事件

  1. dispatchTouchEvent
    dispatchTouchEvent 方法作为 view 的事件处理的 API 入口,内部会调用 onInterceptTouchEvent 和 onTouchEvent 来计算返回的 boolean 值,一般我们都不会动 dispatchTouchEvent 方法,因为没有意思。但是我们直接返回 true 时,表示我消费这个事件了

  2. onInterceptTouchEvent
    onInterceptTouchEvent 方法默认是返回 false 的,表示不会拦截这个事件,但是若是返回 true 则表示这个事件我拦截住了,就不再往我下一级 view 传递了,然后会把事件交给自己的 onTouchEvent 方法

  3. onTouchEvent
    onTouchEvent 方法可以获取具体的触控参数,进行手势方向,当前手势类型判断,可以记录触摸点的 x,y 坐标。onTouchEvent 方法若是返回 true ,则表示这个事件我已经处理过了,那么整个事件传递过程就结速了,否则的话这个事件会原路返回,去一级一级的跑上一层 view 的 onTouchEvent 方法,直到有人返回 true 或是没有了。

  4. requestDisallowInterceptTouchEvent
    view.getParent().requestDisallowInterceptTouchEvent(true) ,可以让内层的 view 获取到事件,而忽略上层视图的拦截。true 表示接受事件,fasle 表示不接受事件。原理分析看这里:

事件分发的顺序

总的来说,事件是由其父视图向子视图传递,按前面的图来说是这样。

Activity -> PhoneWindow -> DecorView -> ViewGroup -> ... -> View
  1. window 根据视图树顺序,从外到内遍历所有的 view ,询问每一个遍历出来的 view 你要不要消费触摸事件
  2. 每个 view 会跑自己的 dispatchTouchEvent 方法,判断自己是否需要消费这个事件
  3. dispatchTouchEvent 方法首先会询问 onInterceptTouchEvent 方法,是否要拦截这个事件。
  4. 若是拦截则会跑自己的 onTouchEvent 方法,若不拦截则会传递给下一级 view,调用下一级 view 的 dispatchTouchEvent 方法
  5. onTouchEvent 若是返回 true ,表示事件实际处理过了,那么整个事件传递在这个节点就结速了,不再传递了。若是返回 fasle,这个事件会原路返回,去一级一级的跑上一层 view 的 onTouchEvent 方法,直到有人返回 true 或是没有了。
Snip20181023_27.png 005Xtdi2jw1f88i0q8uozj30nm0kqwhm.jpg 2157910-7d71eb5d5dff748e.png

这个点建议大家去看经典的文章

前人的经典文章我就不逾越了,推荐大家看经典,省的理解错误,这里我放地址

具体的例子我就不写了,大家看这篇文章的例子,设计的很全面

想了解的触控类型和参数还有源码分析的看这里

想更详细了解 MotionEvent 看这里,很详细包括多点触控

我复制一下核心要点:

  • 事件分发原理: 责任链模式,事件层层传递,直到被消费。
  • View 的 dispatchTouchEvent 主要用于调度自身的监听器和 onTouchEvent。
  • View的事件的调度顺序是 onTouchListener > onTouchEvent > onLongClickListener > onClickListener 。
  • 不论 View 自身是否注册点击事件,只要 View 是可点击的就会消费事件。
  • 事件是否被消费由返回值决定,true 表示消费,false 表示不消费,与是否使用了事件无关。
  • ViewGroup 中可能有多个 ChildView 时,将事件分配给包含点击位置的 ChildView。
  • ViewGroup 和 ChildView 同时注册了事件监听器(onClick等),由 ChildView 消费。
  • 一次触摸流程中产生事件应被同一 View 消费,全部接收或者全部拒绝。
  • 只要接受 ACTION_DOWN 就意味着接受所有的事件,拒绝 ACTION_DOWN 则不会收到后内容。
  • 如果当前正在处理的事件被上层 View 拦截,会收到一个 ACTION_CANCEL,后续事件不会再传递过来。

参考资料:


相关文章

网友评论

    本文标题:android 事件分发原理

    本文链接:https://www.haomeiwen.com/subject/qmousftx.html