Android触摸事件传递机制
简单梳理一下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触摸事件传递机制的更多相关文章
- 初识Android触摸事件传递机制
前言 今天总结的一个知识点是Andorid中View事件传递机制,也是核心知识点,相信很多开发者在面对这个问题时候会觉得困惑,另外,View的另外一个难题滑动冲突,比如在ScrollView中嵌套Li ...
- Android触摸事件传递机制,这一篇就够了
整个触摸事件牵涉到的是,Activity,View,ViewGroup三者的传递机制. 这个触摸事件就是从外层往内层一层层的传递. 整个传递机制,分为3个步骤:分发,拦截,和消费. 1. 触摸事件的类 ...
- Android touch 事件传递机制
前言: (1)在自定义view的时候经常会遇到事件拦截处理,比如在侧滑菜单的时候,我们希望在侧滑菜单里面有listview控件,但是我们希望既能左右滑动又能上下滑动,这个时候就需要对触摸的touch事 ...
- Android 的事件传递机制,详解
Android 的事件传递机制,详解 前两天和一个朋友聊天的时候.然后说到事件传递机制.然后让我说的时候,忽然发现说的不是非常清楚,事实上Android 的事件传递机制也是知道一些,可是感觉自己知道的 ...
- Android Touch事件传递机制引发的血案
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38942135 关于Android Touch事件传递机制我之前也写过两篇文章,自觉得对Tou ...
- Android Touch事件传递机制 二:单纯的(伪生命周期)
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
- Android Touch事件传递机制 一: OnTouch,OnItemClick(监听器),dispatchTouchEvent(伪生命周期)
ViewGroup View Activity dispatchTouchEvent 有 有 有 onInterceptTouchEvent 有 无 无 onTouchEvent 有 有 有 例 ...
- iOS 和 Android 触摸事件传递
先看文章,写得很好 ios 触摸事件传递 http://www.cnblogs.com/Quains/p/3369132.html 另外一篇 http://blog.csdn.net/yongyinm ...
- 【转】Android TouchEvent事件传递机制
Android TouchEvent事件传递机制 事件机制参考地址: http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html ht ...
随机推荐
- 快速获取.NET DLL文件编译时间
当用户现场汇报问题给我们, 我们比较关心的就有用户现场的DLL是什么版本号,是什么时候编译的. 有没有什么办法得到呢?办法是有的. 在网上找了很久终端找到这个软件非常地好用. 直接把文件拖到软件里就行 ...
- angular 响应式表单
- angular HTML属性绑定
- 「HNOI2008」越狱
题目链接 戳我 \(Solution\) 正难则反,这道题直接做有点困难,但我们可以反过来思考我们可以用总方案数减去不可以越狱的方案数 首先来算总方案数: 对于每个房间的人都有\(M\)种宗教可以选, ...
- OC 术语表
术语表 本附录包含了很多会用到的非正式定义术语.有些术语与Obective-C语言有关,其他术语则有自己的语源,来自面向对象程序设计的规范.在后一种情况中,术语的含义只有明确应用于Obective-C ...
- 跳转iPhone设置页面,绕过审核
1.问题描述 跳转iPhone设置页面之前都是通过 App-Prefs:root=WIFI 来跳转,但是2018年6月废弃了这个函数,被认为是私有函数,审核会被拒绝. 有心人采用了字符串转码的方式来规 ...
- Thread Group(线程组)
线程组,可以理解用户池,用来产生线程(用户),每一个线程代表一个用户,在使用JMeter进行性能测试过程中,经常需要模拟多个用户进行测试,可以通过设置线程数代表多少个用户,通常一个线程组就代表一个测试 ...
- win7系统电脑显示windows副本不是正版怎么办
win7系统电脑显示windows副本,可以:在开始输入框中输入cmd——以管理员权限运行——在命令行中输入SLMGR -REARM,——重启.
- 【转】C# datagridview大小跟随窗口动态改变
源地址:https://blog.csdn.net/fengxing11/article/details/52527715
- BZOJ 1061 [Noi2008]志愿者招募(费用流)
题目描述 申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者.经过估算,这个项目需要N 天才能完成,其中第i ...