研究了一下android的touch事件,从doc到google,算是有了一些初步的理解。以下是经过消化的个人理解,有可能与事实不符,欢迎指正。
首先,来了解一下android的事件机制。android的基本元事件我猜应该有5种,理由是MotionEvent类里有5个事件常量,分别是 ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL和ACTION_OUTSIDE。其中 DOWN/MOVE/UP是人为触发的,CANCEL是系统触发,至于OUTSIDE,doc里写是当事件发生在UI元素之外的时候出发,但实际上我还从 来没有成功触发过这个事件。也许你会觉得按钮按下,然后移出按钮边界会触发这个事件,但很遗憾实际上不会。
也就是说,其实我们能够用到的元事件只有三种,DOWN/MOVE/UP,就像三原色调配出多彩的世界,android其余的复杂事件都是由这三个元 事件组合而成的。比如scroll(滚动)/fling(就是DOWN然后快速的MOVE一小段距离然后UP)/longpress(长按) /singletapup(单击)等等……
那么系统是怎么响应这些事件的呢?响应事件的方法有几种。
最简单也是最常用的是实现一个OnClickListener的接口,然后用view的setOnClickListener方法绑定这个接口,就可 以处理view的单击事件。这种方法简便易行,但是只能处理单击这一种事件。实际上,click这个事件是顺序触发ACTION_DOWN和 ACTION_UP两个事件组成的,中间可以存在ACTION_MOVE,但不能MOVE出view的边界,不然即使再MOVE回来也不能触发click 事件了。OnClickListener接口的onClick方法是在click事件的ACTION_UP的timing执行。onClick方法只有一 个参数,就是被单击的View,这种方法是不能获取单击事件的,也就无法获取单击点的坐标等属性。
第二种略微复杂一点的事件处理方法是用OnTouchListener接口而不是OnClickListener,实现方法跟上面一种差不多,实现这 个接口的onTouch(View v, MotionEvent e)方法之后,就可以响应touch的元事件了,注意,是元事件!也就是说,一次简单的click事件会在DOWN和UP的时候分别执行onTouch方 法各一次(如果是scroll一下会触发一次DOWN和很多次的MOVE)。同时,由于有了MotionEvent的参数,我们可以用 e.getAction()来获取元事件类型或者e.getX()/e.getY()来获取事件发生点的坐标,以及许多其他的事件属性。这样,能干的事情 就多那么一点点了。这个方法还有一个boolean的返回值,至于这个返回值是做什么用的,一会儿再交代。
第三种是连接口都用不着,而是直接覆写一个现成的方法view.onTouchEvent(MotionEvent e),这个方法和onTouch方法的不同,直观上来讲,没有view参数了。那这个方法不就没有onTouch方法强大了?那要它有啥用呢?这就要从android的事件传播机制讲起了。
android的事件传播机制跟网页W3C的标准有一点点类似,都是一个事件产生之后经过一个由上到下的捕捉过程再经过一个由下到上的冒泡过程。但是 不同的是,android事件在传播过程中的某一层如果被消费了,就会终止传播。也就是说,发生在一个按钮上的ACTION_DOWN事件实际上是先发生 在他的父父父父控件(某一个ViewGroup)上然后再层层传过来的,按钮如果消费这个事件,那么传播终止(如果他爸爸消费了这个事件,那么按钮就悲催 地根本获取不到这个事件),如果它不消费这个事件,那么这个事件又会冒泡回去,过程大致是这样。
具体来讲,android的事件产生以后,捕捉过程是由ViewGroup.onIntercepTouchEvent(MotionEvent e)传递的,即产生之后,由上向下,依次传递给子ViewGroup的onInterceptTouchEvent方法。这个方法有个boolean的返 回值,false表示本人不消费这个事件,这个事件继续传给我儿子。true表示本人留下这个事件啦,捕捉过程到此为止,不传给儿子了。儿子的 onInterceptTouchEvent方法就不会再执行了。注意,这个方法只有在ViewGroup里有,而最孙子的View里是没有的,因为到 View为止,捕捉过程一定会结束。
那么,捕捉过程终止过后,冒泡过程是由谁来处理的呢?答案就是onTouchEvent方法。当捕捉过程达到最孙子的View(我知道应该叫叶子 View……),或者某一层的ViewGroup的onInterceptTouchEvent返回值为true的时候,该View或者该 ViewGroup的onTouchEvent方法就会执行,这个方法同样会返回一个boolean,false代表我不消费这个事件,这个事件冒泡回去 孝敬我爸爸,true表示我消费啦,事件传播就此终止。而冒泡回去的事件,就由上一层的onTouchEvent来处理。这就是说,网页的事件是捕捉冒泡 走一条线,并且默认不会被消费而阻断的(关于网页事件的流程,感谢stauren提供技术支持),而android的事件则是捕捉冒泡分两个方法线来完 成,一旦某一个节点消费了这个事件,事件就停止传播了。
写到这里,有人可能会发现一个问题。什么叫“事件被消费了”?不就是事件被处理了么?如果我把事件处理的方法写在 onInterceptTouchEvent/onTouchEvent里,但是返回值却是false,那么不就做到,既处理了事件,又没有停止事件传 播,不就跟网页一样了么?(这种需求实际工作中非常有用!)
愿望是好的,但实际操作一下,你就会发现,除了ACTION_DOWN事件以外,其余的事件你都只有返回值是true的那个方法才能捕捉的到。这是为 什么呢?为什么DOWN事件又可以呢?这是因为,android的事件传播只有在第一个事件发生的时候(所有事件第一个发生都是DOWN,你得先把手按上 去嘛……)按前述顺序进行一次,找到那个返回值是true的方法,然后,所有后续事件都会直接传给那个View,不再经历中间的传播过程!所以,中间路径 上的那些返回false的方法,只能捕捉到每次的第一个DOWN事件,而后续的MOVE和UP事件就捕捉不到了。
那么有没有办法能够让消费之后传播过程继续呢?有,只要你在返回true的方法里人为调用上一层的onTouchEvent或者下一层的onInterceptTouchEvent,传播不就进行下去了么?
最后,处理复杂的三元事件的组合事件,android提供了一个GestureDetector类,实现 GestureDetector.GestureListener接口之后(就是各种onLongPress/onFling/onScroll等方法) 并实例化一个GestureDetector对象之后,就可以在本来要处理事件的onTouchEvent方法里人工调用这个detector实例自带的 onTouchEvent方法,改由detector来处理事件,于是各种复杂事件就能被识别和处理了。
分享到:
相关推荐
本文将深入解析Android的Touch事件分发机制,并通过一个名为"EventDispatchTest"的示例来说明。 1. **事件分发流程** Android中的触摸事件分发分为三个阶段:`dispatchTouchEvent()`, `onInterceptTouchEvent()`, ...
首先,Android的触摸事件主要包括ACTION_DOWN、ACTION_UP、ACTION_MOVE、ACTION_CANCEL和ACTION_POINTER_DOWN/UP等几种类型。当用户触摸屏幕时,这些事件会在View层次结构中逐级传递,形成所谓的"事件流"。事件流...
为了解决这个问题,可以使用两种方法:第一种是通过在校准程序里面得到整个屏幕的分辨率,进而让校准程序全屏显示,即把导航栏隐藏。第二种是通过 JNI 种获取系统的分辨率,这种方法需要 apk 有 root 或者 graphics ...
在Android平台上,我们可以实现一个类似于iOS的Assistive Touch功能,这个功能通常被称为悬浮按钮,它提供了一种便捷的方式,让用户快速访问常用设置或功能。本文将深入探讨如何在Android应用开发中创建这样一个仿...
Qt for Android的触摸手势事件通过QGestureEvent提供了一种强大且灵活的方式来处理用户在Android设备上的触摸输入。通过理解和利用QGestureEvent及其相关类,开发者可以创建出高度互动、响应式的Android应用,提供...
随着移动设备技术的发展,多屏显示逐渐成为一种新的交互方式,特别是在汽车信息系统中,这种技术的应用越来越广泛。在Android O系统中,实现了一个多屏Touch方案,并且已经在实际产品中得到应用。本文将详细介绍这一...
TouchDelegate是Android提供的一种机制,允许将一个View的触摸区域扩大到其他View。这对于需要增大点击区域或实现非矩形形状的点击效果非常有用。 9. MotionEvent中的坐标系统 MotionEvent的坐标系统分为屏幕坐标...
在Android平台上实现类似iPhone的AssistiveTouch手势功能,是一种为用户提供便捷操作的途径,它可以在屏幕边缘或浮动窗口上提供一系列快捷操作。这个开源项目是开发者为了满足这一需求而创建的,使得Android用户也能...
"Android-AssistiveTouch"是一个开源项目,旨在帮助用户在Android设备上实现类似iOS中的"小白点"功能,提供一种便捷的触摸操作方式。该项目特别适用于那些已经开启沉浸式模式并隐藏了虚拟按键的Android手机,如Nexus...
### Android事件分发机制详解 #### 一、触摸事件涉及的核心类 在Android系统中,触摸事件主要由两类核心对象负责处理:`ViewGroup` 和 `View`。 1. **ViewGroup**:作为容器,继承自 `View`,用于容纳多个 `View`...
总的来说,"SoundTouch变声"项目结合了Android的JNI技术、SoundTouch音频处理库以及录音和播放功能,为用户提供了一种创新的变声体验。通过深入理解JNI的工作原理,以及掌握音频处理和变声算法,开发者可以打造出...
PhoneGap和Sencha Touch是两种在移动应用开发中广泛使用的框架,它们的结合可以让你创建跨平台的原生感观的Android应用程序。本教程将深入探讨如何利用PhoneGap和Sencha Touch 2.0来构建Android应用。 PhoneGap,现...
在`TouchDemo`这个示例项目中,开发者可能已经创建了一个包含多个视图层次的布局,并通过重写`onInterceptTouchEvent`和`onTouchEvent`来演示这两种方法的交互。通过调试和日志打印,我们可以清晰地看到事件如何在...
触摸事件(Touch Events)主要涉及手势操作,如按下(`ACTION_DOWN`)、移动(`ACTION_MOVE`)、释放(`ACTION_UP`)等。这些事件通常用于处理用户的滑动、拖拽等复杂交互。而点击事件(Click Events)则相对简单,...
在Android开发中,创建悬浮窗(FloatWindow)是一种常见的需求,它可以实现类似系统通知栏、桌面小部件等效果。在实现悬浮窗时,我们经常需要处理用户的触摸交互,包括单击(onClick)和滑动(onTouch)事件。标题...
Android中的触摸事件主要分为三种基本动作:ACTION_DOWN、ACTION_MOVE 和 ACTION_UP。 - ACTION_DOWN:当用户手指首次接触屏幕时,系统会产生一个ACTION_DOWN事件,标志着触摸的开始。 - ACTION_MOVE:如果用户在...
Raycast 是 Unity3D 中的一种射线检测技术,可以用来检测场景中的对象是否被选中。在本示例中,我们使用 Raycast 来检测当前选中的对象,并获取其 collider 组件,然后根据手指的移动来控制对象的旋转和平移。 三、...
悬浮窗是Android系统中一种特殊类型的窗口,它可以在其他应用之上显示,允许用户在进行其他操作时快速访问特定功能。实现悬浮窗主要涉及到`WindowManager`服务和`LayoutParams`类。`WindowManager`用于管理应用的...
在Android开发中,手触事件(Touch Event)是用户与应用程序交互的重要部分。手触事件处理涉及到了Android的UI框架,主要包括View、 ViewGroup 和 MotionEvent 类。本实例将深入探讨如何在Android应用中处理这些事件...