对Android中Touch事件分发机制的理解和总结

来源:互联网 发布:usb hi speed mac驱动 编辑:程序博客网 时间:2024/05/10 04:26

这篇文章是对他人文章的一个总结。
主要参考了郭霖大神的博客

http://blog.csdn.net/guolin_blog/article/details/9153747

和国外一个哥们的视频

http://v.youku.com/v_show/id_XODQ1MjI2MDQ0.html

水平太菜,从源码角度来看的话自己都被搞混乱了,所以就从“外在表现”的角度总结一些结论,这样能使自己清楚一点,等到自己能分析源码了,再从源码的角度写一篇总结。tips:上面两个大神的教学内容结合起来看风味更佳~

以下是我的总结:

  • Android只定义了一种手势(gesture),此手势的全部事件(event)组成发生在动作ACTION_DOWN和ACTION_UP之间,一个DOWN和UP是一次重新开始。

  • 如果View没有对DOWN进行消费,那么它将不能接收到手势中接下来的事件。

  • 事件最先被发送到当前Activity,然后再传给子ViewGroup,子ViewGroup再传递给子View,如果没有感兴趣的视图,事件就返回向上传递,最后传递给当前Activity,这是一个完整的传递链。如果传递过程中某个View“宣布”对这个事件感兴趣。系统就会中断默认的传递链,这个视图就是某个手势中其他事件的直接目的地。

  • 更具体地看一下传递链——Activity的dispatchTouchEvent调用子ViewGroup的dispatchTouchEvent方法,ViewGroup的dispatchTouchEvent调用子View的dispatchTouchEvent,不断将事件向下传递,如果事件没有被消费,各级View的onTouchEvent方法将事件向上回传。 (这里只是根据源码说了一下大概的事件分发流程,肯定有疏漏的地方)

  • 在大部分情况下,onTouch方法和onTouchEvent方法效果相同,同样可以返回true来消费事件。

  • View的dispatchTouchEvent方法比ViewGroup的dispatchTouchEvent方法要简单~它干两件事:检查监听器内是否消费事件、检查onTouchEvent是否消费事件。如果这两个地方都返回false,即View的dispatchTouchEvent返回false,那么对于上层的ViewGroup,会调用自己的onTouchEvent。

  • ViewGroup的dispatchTouchEvent的机制有点复杂。首先它要对子View进行管理,根据坐标来确定和事件相关的子View,然后调用相关子View的dispatchTouchEvent方法 (如果有多个子View相关,将会按子View被添加到ViewGroup中的逆序,调用其dispatchTouchEvent)。其次ViewGroup可以对事件进行中断或者说窃取——通过onInterceptTouchEvent方法,此方法不断监测触摸事件,监测哪些流入到此ViewGroup中,可能由于手势的特殊要求,ViewGroup会停止将事件分发给子View,转而由自己处理,例如有一个ScrollView中含有一个Button,点击的事件可以往下分发,但是滚动的动作就要被ScrollView拦截下来,接下来会在自己的onTouchEvent中处理接下来的事件,所以我们可以在onInterceptTouchEvent里监测ViewGroup需要自己处理的动作并返回true,这样就完成了拦截。综上所述,事件的分发,都是由ViewGroup监测,并且决定如何处理(传给子View或者自己处理)。

  • 分发给ViewGroup的事件,被分发下去之前都会检查onInterceptTouchEvent的返回值,一旦某个时刻onInterceptTouchEvent返回true,关于此手势的当前事件以及后续事件直接在ViewGroup自身的onTouchEvent中处理,且不可逆转,作为一个ViewGroup而言,一旦决定对子View进行事件屏蔽,就要吸收后续事件。

  • 子View可以在一个手势内暂时性的阻止父视图的onInterceptTouchEvent方法。
  • 视频中的例子:1个FrameLayout+1个普通View。这个View可以导致其onTouchEvent返回false(因为不可点击)。一个点击的DOWN事件没有View或ViewGroup消费,最终被传回了Activity的onTouchEvent中,后续的事件将不再被Activity分发下去。
    这里写图片描述

  • 视频中的第二个例子:1个FrameLayout+1个Button,由于Button对点击手势进行消费,在对DOWN事件消费以后,接下来的MOVE和UP也将在Button的onTouchEvent中进行消费。(这些机制都是在源码中实现的,我们现在只看结果。其实我们可以预见,在Activity和ViewGroup的dispatchTouchEvent方法至少有两处return,一处是调用子View的dispatchTouchEvent的地方,一处是调用自己的onTouchEvent的地方,在一处return了就不可能在另一处return)
    这里写图片描述

  • 视频中的第三个例子:1个ScrollView中含有1个Button,手势是按住以后拖动,首先DOWN的动作被Button消费,接下来的事件本应该传递到Button处进行处理消费,在一系列MOVE事件发生时,被ScrollView的onInterceptTouchEvent监测到并返回true,事件不再从ScrollView的dispatchTouchEvent中往下分发,转而由自己的onTouchEvent处理,Button接收到事件CANCLE。
    这里写图片描述

以上这些都是从最终表现和简单的源码解读来总结的对事件分发机制的理解,肯定有错误的地方,还有很多细节要从源码的角度来看。随着不断的学习,我也会更新这篇文章~

0 0