Android触摸事件机制

前言

随着科学技术的发展,智能手机早已成为我们当代人身边必不可少的“伙伴”之一,堪比对象女友。每天我们对着手机重复的做着点击滑动操作,而手机则随着我们的操作给我们展示她的精彩。

废话到此结束。

看到这里,即使不是作为移动端码农的你也应该知道触摸事件对手机(经典键盘机除外)的重要性了。

什么是触摸事件

顾名思义,就是触摸手机屏幕后产生的事件。这时候请你拿出手机,点击屏幕中的某个按钮(不要松手),移动一段距离,松手。

这个过程一般会产生如下几个事件:

  1. 点击(Down)事件
  2. 移动(Move)事件
  3. 松手(Up)事件

Android为我们封装好了一个触摸事件类MotionEvent,上述的三个过程分别对应着MotionEvent中的MotionEvent.ACTION_DOWNMotionEvent.ACTION_MOVEMotionEvent.ACTION_UP事件类型,我们可以以此来实现不同的逻辑,即事件的分发处理。所谓触摸事件的分发,实际上可以理解为MotionEvent事件的分发过程,即当一个MotionEvent产生了之后,系统需要把这个事件传递给一个具体的View,而这个传递的过程就是分发过程。

事件三剑客

一般事件的分发过程是由事件三剑客(方法)来共同完成的。

/**
 * 剑客一:用于事件的分发
 */
public boolean dispathTouchEvent(MotionEvent ev)

/**
 * 剑客二:在剑客一种被调用,用于事件的拦截
 */
public boolean onInterceptTouchEvent(MotionEvent ev)

/**
 * 剑客三:在剑客一种被调用,处理点击事件,true:消耗了当前事件  false:当前view无
 * 法再次接收事件
 */
public boolean onTouchEvent()(MotionEvent ev)

三剑客的关系如下图所示(以Activity的dispathTouchEvent为例)

分析可知:

1. 触摸事件ev类收到点击的ACTION,会回调onUserInteraction方法,一般项目中我们把一些需要用户开始触摸时就需要执行的任务代码放在这里。

2. 接下来触摸事件ev会传递给Activity窗口绑定的根视图rootView(View/ViewGroup),如果根视图也有子视图,事件ev会一级一级的分发下去,如果在这个过程中ev被消耗了,事件就此结束分发,否则进入步奏3。

3. 所有的视图布局都没有消耗掉ev事件,就会调用Activity的onTouchEvent()方法。下面会具体讲诉。

Android界面简析

在具体讲诉前,我们先来了解下的android的界面架构。如果说手机是一个学校,那么手机中的每一个APP(应用)都是学校里的一道道独特风景,正是它们,构成了学校的魅力。而每个APP都是由一个个Activity组成的。

还是在说废话…

如下图所示,我们清晰的看到每个Activity都会包含一个Window对象。而window对象通常由PhoneWindow来实现。PhoneWindow将一个DecorView设置为整个应用窗口的根View。它将屏幕分成两部分,一个是TitleView,另一个是ContentView(也就是大家熟悉的ContentView布局)。ContentView是一个ID为contentFrameLayout,而我们一直写的activity_xx.xml布局就是设置在这样一个FrameLayout里。

DecorView将要显示的具体内容呈现在了PhoneWindow上,这里面的所有View的监听事件(点击、滑动等操作)都通过一个名为WindowManagerService来进行接收(具体可看深入理解android卷三),并通过Activity来回调相应的监听。

为了让大家更好的理解,我们来写一个小demo如下

运行结果如图

小场景,见真理

场景一

我们写一个最简单的demo如下

运行程序,点击button,看到log输出如下:

修改dispathTouchEvent,直接return false

运行程序,点击button,是不是看到控制台什么都没有输出。可见事件传递到activity的根视图就被结束分发了。下面已场景二来具体探究下这个过程。

场景二

假如在大学中,学校交给了数学老师一个任务,老师讲这项任务布置给了女班长,而女班长又将这个任务交给了帅气的我,我千辛万苦的将这个任务完成了,然后交给了女班长,女班长觉得完成的不错,夸了帅气的我几句(暗恋上了),然后将任务提交给了老师,老师看了下也觉得完成的不错,就把任务提交给学校了。

依据上面的场景,我们设计一个场景实例如下

  1. 老师——TeacherViewGroup
  2. 女班长——MonitressViewGroup
  3. 帅气的我——HandsomeMyView

布局层次如下图所示

TeacherViewGroup和MonitressViewGroup代码如下,重写了三剑客方法

HandsomeMyView代码如下,view是没有剑客2(方法)onInterceptTouchEvent()

点击帅气的我可以看见log打印如下

可以看见一般事件都有两个过程

  • 传递过程 : 老师(TeacherViewGroup)——>女班长(MonitressViewGroup)——>帅气的我(HandsomeMyView)
  • 处理过程 : 帅气的我(HandsomeMyView)——>女班长(MonitressViewGroup)——>老师(TeacherViewGroup)

传递的过程方法:剑客1(dispatchTouchEvent)、剑客2(onInterceptTouchEvent)

处理的过程方法:剑客3(onTouchEvent)

为了让大家更好的理解,整理视图如下:

从中我们看出触摸事件ev会按照子View加入ViewGroup先后顺序相反的顺序,依次有机会去消费此触摸事件ev,即最后加入的最先有机会消费此触摸事件(消费的前提是,触摸点在这个子View的视图范围之内)。简而言之,传递由外向内,消费(处理)由内向外。

在前面的事件三剑客中细心的同学会发现,他们的返回值都是boolean类型,那么true和false分别代表什么意义呢?

在这里我先告诉大家结论,然后在验证这个结论:

dispatchTouchEvent()onInterceptTouchEvent()

  • 返回true表示事件被拦截,不继续;
  • 返回false表示事件不被拦截,继续下一步流程;

onTouchEvent()

  • 返回true表示事件被处理了,不用传递给上一级视图;
  • 返回false表示事件交给上一级视图处理;

初始情况下他们的默认返回值都为false

拦截onInterceptTouchEvent()

假设女班长暗恋帅气的我,自己偷偷帮我完成了任务,这时候事件就被女班长(MonitressViewGroup)的onInterceptTouchEvent()方法拦截了,即MonitressViewGrouponInterceptTouchEvent()返回ture,此时Log输出如下

整理视图如下:

同样的,也可以假设老师人比较好,不忍心麻烦学生,自己处理了,这个过程类似女班长处理过程。

到这里,我想大家对事件的分发、拦截已经有一个比较清楚的认识了。接下来我们来看下事件的处理。

处理onTouchEvent()

我们处理完任务后是需要将完成结果汇报给上级的,也就是帅气的我需要向我亲爱的女班长汇报结果,班长向老师汇报结果。假设我不能按时完成任务,没将任务结果汇报给女班长,也就是HandsomeMyView的onTouchEvent()方法返回true(事件被处理了,不用返回给上级),此时Log输出如下,女班长和老师不用继续处理事件了

整理视图如下:

同样的,女班长和老师也可以不像他们各自的上级汇报,过程类似帅气的我(HandsomeMyView)。

Ref

  1. Mastering the Android Touch System
  2. Android群英传

时间: 2024-10-28 19:33:45

Android触摸事件机制的相关文章

Android中TouchEvent触摸事件机制

当我们的手指在Android屏幕上点击或滑动时,就会触发触摸事件TouchEvent.在App中ViewGroup和View存在多级嵌套,在最外层的是Activity,最内层的View,介于Activity与View之间的是一些ViewGroup.本文为了简化讨论,我们假设一个Activity中只有一个ViewGroup,这个ViewGroup中只有一个View.当我们用手指触摸到View的UI时,就会产生触摸事件TouchEvent,总的过程如下图所示: 首先是最外层的Activity接收到该

Android触摸事件分发机制完全解析《一》

最近在做高德地图的时候,由于用户的要求,不得不用ScrollVew嵌套MapView,虽然很官方要求不建议这样做,但也迫于无奈- 魔高一尺,道高一丈.有什么事情事程序员不能解决的,如果有那就是解决两次. 鉴于用到了触摸事件,于是就来总结了Android的触摸事件机制. 首先当用户进行屏幕操作的时候,则有两种情况 一是按键事件 二是触摸事件 按键事件分为长按和点击事件,过于简单,这里不再进行总结. 触摸事件 触摸事件的组成: - 一个actionDown - n个actionMove - 一个ac

Android 触摸事件处理机制

Android 触摸事件的处理主要涉及到几个方法:onInterceptTouchEvent(), dipatchTouchEvent(), onTouchEvent(), onTouch(). onInterceptTouchEvent() 用于拦截事件并改变事件传递方向.解释一下事件传递.比如一个Activity中展示给用户可能是ViewGroup和View的多层嵌套,默认情况下触摸事件产生之后从最外层一次传递到最里面一层,然后在从最里面一层开始响应.从最里面一层开始依次调用各层次的disp

聊一聊Android的事件机制

侯 亮 1概述 在Android平台上,主要用到两种通信机制,即Binder机制和事件机制,前者用于跨进程通信,后者用于进程内部通信. 从技术实现上来说,事件机制还是比较简单的.从大的方面讲,不光是Android平台,各种平台的消息机制的原理基本上都是相近的,其中用到的主要概念大概有: 1)消息发送者: 2)消息队列: 3)消息处理循环. 示意图如下: 图中表达的基本意思是,消息发送者通过某种方式,将消息发送到某个消息队列里,同时还有一个消息处理循环,不断从消息队列里摘取消息,并进一步解析处理.

iOS 和 Android 触摸事件传递

先看2篇文章,写得很好,都是咱们博客园的博文 ios 触摸事件传递 http://www.cnblogs.com/Quains/p/3369132.html android 触摸事件传递 http://www.cnblogs.com/superlcr/p/3946034.html 读完这2篇文章,可以发现ios和android对触摸事件的处理的大体思路是一致的,都是从根view开始,遍历检测子view,找到适合的view触发具体事件.2个平台都具备分发触摸事件,拦截触摸事件传递的机能. 下面盗用

Android触摸事件分发机制

Android中的事件分为按键事件和触摸事件,这里对触摸事件进行阐述.Touch事件是由一个ACTION_DOWN,n个ACTION_MOVE,一个ACTION_UP组成onClick,onLongClick,onScroll等事件.Android中的控件都是继承View这个基类的,而控件分为两种:一种是继承View不能包含其他控件的控件:一种是继承ViewGroup可以包含其他控件的控件,暂且称为容器控件,比如ListView,GridView,LinearLayout等. 这里先对几个函数讲

Android 触摸事件 点击事件的分发机制 详解

最近发现团队里有些员工在做一些自定义控件的时候感觉比较吃力.尤其是做触摸事件这种东西的时候.很多人对机制并不理解.因为百度出来的东西都太理论化了.确实不好理解. 今天带大家坐几个小demo.帮助理解一下. 先从简单的view 的事件分发机制开始解释. 我们首先自定义一个工程 package com.example.testtouch; import android.app.Activity; import android.os.Bundle; import android.util.Log; i

android屏幕触摸事件机制(转)

android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件,有必要对它进行深入的了解.一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOVE->ACTION_UP当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是ViewGro

Android触摸事件

简介: 做了一个语音发送UI的小demo. 按下显示语音窗口,根据音量调节UI音量显示,上划至窗口显示取消发送. 原理: 1:获取什么事件来执行操作: 给Button添加setOnTouchListener事件,获得触摸事件,在滑动事件中得到当前显示控件的坐标,然后根据当前触摸位置与坐标进行判断来确定是否取消.在触摸离开的事件中来确定是否处理发送的请求. 2:更新音量值: 在线程中得到录音的音量大小,然后用handler发送到activity中进行UI更新. 详解事件: 通过public boo