安卓事件分发机制之简明教程

来源:互联网 发布:淘宝联盟api 优惠卷 编辑:程序博客网 时间:2024/06/16 18:02

前言

视频版:http://v.youku.com/v_show/id_XMTY5MjczMjE3Ng==.html。
半年前曾写过一篇《浅尝安卓事件分发机制》,当时很引以为傲,虽然访问量惨淡。

现在重读之,感觉逊毙了——不管是语言表达,还是知识点分析。

于是萌生了写此文的念头。本文抛开代码,不要大而全,但求短、平、快。

控件的摆放方式

如果你听说过 CSS,恰巧还知道它的中文名是“层叠样式表”(Cascading Style Sheet),那么恭喜你:安卓控件也是以这种“叠罗汉”的方式摆放的。而且,控件都是矩形的,那些非矩形是控件透明区域给眼睛造成的错觉。

当我们的手指点击屏幕时,落点可以换上成一个(x, y)坐标,这个坐标必然落在多个控件的区域内。假设落点是一个密度无限大的奇点,那么这个点将穿透多个控件。这些控件,就是这个点击事件潜在的交互目标。

事件的类型

为简单起见,只考虑单点触控。

  • ACTION_DOWN(以下简称 DOWN)
  • ACTION_MOVE(以下简称 MOVE)
  • ACTION_UP(以下简称 UP)
  • ACTION_CANCEL(以下简称 CANCEL)

我们滑动朋友圈列表时,手指从按下到滑动再到松开,分别对应三个事件:DOWN -> MOVE -> UP。

当一个控件消费了 DOWN 事件,但是后续事件被父控件拦截时,它将接收到 CANCEL 事件。以点赞为例,手指按下去,红心变亮,说明红心这个控件消费了 DOWN 事件;但是别抬手指,划一下,这是列表滑动,红心由亮变空,MOVE 事件被父控件——列表拦截并消费,列表此时向红心控件分发一个 CANCEL 事件,告诉它“别傻等了,后续事件我要了”。

分发过程的参与者

Window,Activity,View 树

关键方法

dispatchTouchEvent(), onTouchEvent()。
其中,dispatchTouchEvent() 方法是核心。Activity、View、ViewGroup 都有 dispatchTouchEvent() 方法,其中 ViewGroup 继承 View 并重写了该方法。

分发过程

在 Framework 层,从 Window 开始,依次传递给 Activity 和 View 树。

在 ViewGroup.dispatchTouchEvent() 方法中,先调用 onIntercetpTouchEvent() 方法,如果返回 true,则直接执行自己的 OnTouchListener 和 onTouchEvent();如果返回 false,则遍历自己所有的子 View,寻找包含点击位置的子 View,找到后就调用其 dispatchTouchEvent() 方法,重复上述过程。

在这个递归过程中,每个 ViewGroup 的 dispatchTouchEvent() 都在等着自己的子 View 执行完毕自己的 dispatchTouchEvent() 方法。子 View 的 dispatchTouchEvent() 方法执行完毕后,ViewGroup.dispatchTouchEvent() 方法接着执行,或返回 true,或执行自己的 OnTouchListener 和 onTouchEvent()。

上述是 DOWN 事件的分发过程。如果 View 树种没有 View 消费,则后续事件就直接在 DecorView 中处理了,不再下发;否则,后续事件根据标记,省掉遍历子 View 的过程,直接传递给每一层对应的 View,继续调用 dispatchTouchEvent() ,重复 DOWN 事件的处理过程。





1 0