简单梳理一下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. 国外物联网平台(5):Exosite Murano

    国外物联网平台(5)——Exosite Murano 马智 定位 Murano是一个基于云的IoT软件平台,提供安全.可扩展的基础设施,支持端到端的生态系统,帮助客户安全.可扩展地开发.部署和管理应用 ...

  2. sql server重建系统数据库

    方法一:https://bbs.csdn.net/topics/100013082 方法二:http://blog.51cto.com/jimshu/1095780 *** 方法三:https://b ...

  3. SOA IN Real World

    微软发布了一个名为“真实世界里的面向服务架构(SOA)”的电子书.这本书表达了微软对面向服务架构的观点,并包括了数个展示如何用微软产品和技术实现SOA的真实案例.书中解释到,SOA的功能型架构本身是松 ...

  4. hive的安装与配置 mysql安装 启动

    三种模式 内嵌模式:元数据保持在内嵌的derby模式,只允许一个会话连接 本地独立模式:在本地安装Mysql,吧元数据放到mySql内 远程模式:元数据放置在远程的Mysql数据库 1.下载Hive安 ...

  5. poi将图片导入excel(Java代码)

    package com.fh.util;import java.awt.image.BufferedImage;  import java.io.ByteArrayOutputStream;  imp ...

  6. 【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分/LCT+贪心

    Description 给你一个有n个点的树,每个点的包括一个位运算opt和一个权值x,位运算有&,l,^三种,分别用1,2,3表示. 每次询问包含三个数x,y,z,初始选定一个数v.然后v依 ...

  7. 题解 CF500D 【New Year Santa Network】

    题目链接 这道题首先是要看看该如何化简,先把三元组化成二元组. 之后统计经过某条边的 次数$*$权值  的和. 最后除以总基数 $tot$ 其中,每条边被计算的次数为 子树的点数$*$非子树的点数 ( ...

  8. 八大排序算法的python实现(三)冒泡排序

    代码: #coding:utf-8 #author:徐卜灵 #交换排序.冒泡排序 L = [1, 3, 2, 32, 5, 4] def Bubble_sort(L): for i in range( ...

  9. 【数据结构】单链表&&静态链表详解和代码实例

    喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 01 单链表(Singly Linked List ) 1.1 什么是单链表? 单链表是一种链式存储的结构.它动态的为节点分配存 ...

  10. golang包引用解析

    golang包引用解析 环境变量配置如下: GOROOT----[C:\Go] GOPATH----[F:\workspace\go_home] vs code配置如下: F:\workspace\g ...