简单梳理一下Android触摸事件传递机制的知识点。

一、View与ViewGroup的关系

View和ViewGroup二者的继承关系如下图所示:

View是Android中最基本的一种UI组件,它是所有控件类的基类。View类的作用是可以在屏幕上绘制一块矩形区域,并能响应这块区域的各种事件(如触摸事件、点击事件等)。我们平时使用的各种控件其实都是继承自View类,在View的基础上又添加了一些特有的功能。比如TextView可以用于显示文本,进一步还能拓展(extends)为可编辑的文本控件——EditText类或者可点击的文本控件——Button类。

ViewGroup也是继承自View类,但它是一种非常特殊的View,因为它可以作为一个容器来放置其他的控件或布局。我们常用的各种布局Layout类以及ListView、ScrollView等都是继承自ViewGroup。

在讨论Android触摸事件传递机制时,我们这里说的View特指除了ViewGroup以外的View控件,也就是无法作为容器的最小UI单位。

二、Android UI层次结构

Android UI层次结构图和类图如下图所示:

  Activity是Android应用程序的门面和载体,它代表一个完整的用户界面。Activity提供了一个窗口来绘制各种视图,即PhoneWindow类。该类继承自顶层窗口类Window,并且包含一个DecorView类对象。DecorView继承自FrameLayout(帧布局),所以本质上是一个ViewGroup,而且是当前活动所放置的全部View的根视图(RootView)。当我们创建一个活动时,在活动的onCreate()方法中调用setContentView(R.layout.layout_name)方法就是为该活动的ContentView部分指定布局内容从而完成GUI的渲染。

三、事件的类型

事件主要分为触摸事件和点击事件。

1、触摸事件:对应的是MotionEvent类,主要有以下三种类型:

ACTION_DOWN:表示用户手指按下的动作,标志着触摸事件的开始。

ACTION_UP:表示用户手指离开屏幕的动作,标志着触摸事件的结束。

ACTION_MOVE:表示用户手指移动的动作。当用户手指按下屏幕后,在松开之前,只要移动的距离超过了一定的阈值即判定为ACTION_MOVE动作。实际上,即使是手指非常   轻微的移动也会被系统监测到从而判定为ACTION_MOVE动作。

ps:用户触摸屏幕操作由ACTION_DOWN事件开始,结束于ACTION_UP事件,可以有0次或多次ACTION_MOVE事件。

2、点击事件:用户手指按下→停留若干时间(可长可短)→用户手指松开,这一完整的过程视为一次点击事件。可以看出,触摸事件先于点击事件执行。

四、触摸事件传递机制

该机制主要包含三个角色、三个阶段和三个方法。

1、三个角色分别为:Activity、View、ViewGroup。

2、三个阶段分别为:分发(dispatch)、拦截(intercept)和消费(consume)。

3、三个方法的方法原型分别为:

①public boolean dispatchTouchEvent(MotionEvent e)……对应于分发事件

②public boolean onInterceptTouchEvent(MotionEvent e)……对应于拦截事件

③public boolean onTouchEvent(MotionEvent e)……对应于消费事件(即处理事件)

4、解释:

由前面的Android UI层次结构分析可以看出来,一个Activity包含多层视图:先是窗口(PhoneWindow),接着是根视图(即DecorView),然后是具体的ContentView;ContentView视图部分又是各种布局和控件的嵌套组合。那么,当用户做出了触摸动作时,触摸事件应当由哪一个View或者哪一个ViewGroup负责处理呢?这就是触摸事件传递机制要解决的问题。为了方便,下面会用视图这一词代替View或ViewGroup对象。

①在Android系统中,所有触摸事件必须都由dispatchTouchEvent()方法判断是否进行分发。分发事件相当于“传递事件”的一个过程,分发事件的目的就是为了找到正确的视图来处理这个触摸事件。而处理事件的过程就是所谓的消费阶段,调用的方法是onTouchEvent()。如果确定要继续分发事件,向什么地方分发呢?如果是ViewGroup,则是向自己的子视图进行分发;如果是View,向子视图进行分发本质上其实就是分发给自身。如果dispatchTouchEvent()方法返回true,则表示事件由当前视图直接进行消费(处理),不再继续分发;否则,向子视图进行分发。

②除了分发和消费,还有一个拦截操作。须注意的是:只有ViewGroup可以拦截触摸事件,Activity和View只能分发事件和消费事件。这一点其实非常好理解:因为View没有子视图可言,所以不存在拦截的操作;而ViewGroup具有子视图,选择性地进行拦截事件是有意义的。ViewGroup可以调用onInterceptTouchEvent()方法来判断是否拦截该触摸事件。如果该方法返回true,表示拦截该事件不再分发给子视图;否则,表示不拦截事件继续分发给子视图。须注意,ViewGroup类默认是不拦截任何触摸事件的,如果有需要可以重写其onInterceptTouchEvent()方法进行选择性地拦截。

③一旦确定由某个视图负责处理(即消费)触摸事件ACTION_DOWN,那么后续的ACTION_MOVE和ACTION_UP等触摸事件也会同样被该视图捕获。在消费事件阶段,该视图会调用onTouchEvent()方法。如果该方法返回true,那么表示事件被成功消费;如果返回false,那么意味着当前视图没有能力消费该触摸事件,事件会抛给上层的视图调用其onTouchEvent()方法进行处理。

5、触摸事件传递过程:

考虑最一般的情况,即触摸事件ACTION_DOWN由某个View消费掉的情况。事件传递过程分成两步,整个过程都严格遵循上述的分发、拦截和消费的原理。如下图所示:

  

①第一步:先由Activity传递到ViewGroup,具体地讲就是Activity→PhoneWindow→DecorView(根视图)。

②第二步:由根视图DecorView通过一层层的ViewGroup传递到某个子View,由该View负责消费该事件以及后续的事件。

至于其他的情况,比如该View捕获到事件后无法消费抛给上层视图或者某个ViewGroup捕获到事件,则参考下图:

五、something more

除了分发、拦截和消费这三个方法外,还可以在活动中为View类设置监听器接口:

监听触摸事件:setOnTouchListener(),须重写接口的onTouch()方法。

监听点击事件:setOnClickListener(),须重写接口的onClick()方法。

监听长按事件:setOnLongClickListener(),须重写接口的onLongClick()方法

观察View类的源码,有以下结论:

①View的onTouch()方法会先于onTouchEvent()方法执行,并且当前仅当onTouch()方法返回false时,才会执行onTouchEvent()。

②只有当onTouchEvent()方法得到调用,并且触摸事件是ACTION_UP时,onClick()方法才会被调用。这一点逻辑上也非常容易理解,因为当用户手指按下屏幕,只有当他手指离开屏幕触发事件ACTION_UP后才算是一个点击事件。也就是说,当一个View确定捕获触摸事件时,onTouch()方法会介于分发方法和消费方法之间执行,并且只有当其返回false时,后续的消费方法onTouchEvent()才能执行。而只有onTouchEvent()方法成功执行返回true,才能表示触摸事件被正确处理,如果是ACTION_UP被正确处理,那么就会调用onClick()方法。

③这三个监听方法的执行顺序是:onTouch()方法→onLongClick()→onClick() 原因:当用户按下手指后,先执行触摸监听方法;如果用户按下时间超过一个阈值还没有松手,会执行长按监听方法;如果用户最后松开手指,最后执行点击监听方法。并且这三个方法是后者依赖于前者的返回值!只有onClick()返回false,onLongClick()才能执行;只有onLongClick()返回false,onClick()才能执行。

.............................................................................................................................................................over

Android触摸事件传递机制的更多相关文章

  1. 初识Android触摸事件传递机制

    前言 今天总结的一个知识点是Andorid中View事件传递机制,也是核心知识点,相信很多开发者在面对这个问题时候会觉得困惑,另外,View的另外一个难题滑动冲突,比如在ScrollView中嵌套Li ...

  2. Android触摸事件传递机制,这一篇就够了

    整个触摸事件牵涉到的是,Activity,View,ViewGroup三者的传递机制. 这个触摸事件就是从外层往内层一层层的传递. 整个传递机制,分为3个步骤:分发,拦截,和消费. 1. 触摸事件的类 ...

  3. Android touch 事件传递机制

    前言: (1)在自定义view的时候经常会遇到事件拦截处理,比如在侧滑菜单的时候,我们希望在侧滑菜单里面有listview控件,但是我们希望既能左右滑动又能上下滑动,这个时候就需要对触摸的touch事 ...

  4. Android 的事件传递机制,详解

    Android 的事件传递机制,详解 前两天和一个朋友聊天的时候.然后说到事件传递机制.然后让我说的时候,忽然发现说的不是非常清楚,事实上Android 的事件传递机制也是知道一些,可是感觉自己知道的 ...

  5. Android Touch事件传递机制引发的血案

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38942135 关于Android Touch事件传递机制我之前也写过两篇文章,自觉得对Tou ...

  6. Android Touch事件传递机制 二:单纯的(伪生命周期)

    转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...

  7. Android Touch事件传递机制 一: OnTouch,OnItemClick(监听器),dispatchTouchEvent(伪生命周期)

      ViewGroup View  Activity dispatchTouchEvent 有 有 有 onInterceptTouchEvent 有 无 无 onTouchEvent 有 有 有 例 ...

  8. iOS 和 Android 触摸事件传递

    先看文章,写得很好 ios 触摸事件传递 http://www.cnblogs.com/Quains/p/3369132.html 另外一篇 http://blog.csdn.net/yongyinm ...

  9. 【转】Android TouchEvent事件传递机制

    Android TouchEvent事件传递机制   事件机制参考地址: http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html ht ...

随机推荐

  1. HTML & CSS设计与构建网站 ([美]达科特) PDF原版​

    HTML & CSS 设计与构建网站采用有别于许多传统编程书籍的新颖编排方式,将使您收到事半功倍的学习效果.每一页都在短小精悍的示例代码的引导下,简明直观.直截了当地阐述一个新主题. < ...

  2. 【转】android 手势识别和VelocityTracker

    参考地址: http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1020/448.html http://www.jcodecraeer.co ...

  3. 数据库索引与b+树

    数据库索引详解 索引 当我们在设计数据库的时候,对表的一些属性有时会加上索引,但索引为什么能提高检索速率呢?是不是用了索引就一定可以提高效率呢?不同索引之间有什么区别呢?搞懂这些问题是灵活运用索引的必 ...

  4. unix网络编程str_cli使用epoll实现

    unix网络编程str_cli使用epoll实现 unix环境高级编程中也有这个函数,都是为了讲解IO多路转接.从本质上来看epoll就是一个改善了的select和poll,本质没发生任何变化,对于构 ...

  5. windows windows server2003 开机自动挂盘

    windows  windows server2003 开机自动挂盘 方案一: 设置任务计划:开机启动 方案二: 将执行文件放入启动文件夹

  6. StringUtils常用方法介绍

    要使用StringUtils类,首先需要导入:import org.apache.commons.lang.StringUtils;这个包 在maven项目中需要添加下面这个依赖: <depen ...

  7. Can't install Solaris 10 on XenServer 6.5 VM

    I have XenServer 6.5 installed on a server, and i have been trying to install Solaris 10 on a VM, it ...

  8. shell传参给matlab问题解决办法

    之前需要通过shell脚本传参给matlab程序,但是遇到一些问题,现将我遇到的问题分享出来,给遇到同样问题的人一些借鉴. shell部分脚本Execl.sh: /usr/bin/python /ho ...

  9. MyBatis介绍及使用

    一.介绍: 1.MyBatis实际上是Ibatis3.0版本以后的持久化层框架[也就是和数据库打交道的框架]! 2.和数据库打交道的技术有: 原生的JDBC技术--->Spring的JdbcTe ...

  10. how to use windows azure market

    here is the sample. namespace USCrime2006and2007 { class Program { static void Main(string[] args) { ...