Android Touch事件的分发过程

一.不知道你是否在涉及到Android触屏事件的时候有过如下的疑问:

1.View的onTouchEvent()方法返回true和false有什么区别? SDK给出的解释很简单:"返回true代表该事件已经被处理过了,返回false则相反",这句话完全没有解释清楚问题。

2.View的onTouchEvent()方法在处理ACTION_DOWN的时候返回true,在处理ACTION_MOVE的时候返回false,代表着是处理了还是没处理?返回super.onTouchEvent()又是什么含义?

3.重写onTouchEvent()方法和通过setOnTouchListener()设置一个触屏监听有什么区别,看起来好像很类似。

4.View的dispatchTouchEvent(),onTouchEvent(),setOnClickListener(),ViewGroup的onInterceptTouchEvent()把我绕晕了,这些方法怎么使用怎么重写?

5.假设一个ViewGroup有两个子view,这两个view有一部分是重叠的,点击该重叠部分,事件由哪个View来处理?

6.最重要的一点疑问是:触屏事件从顶层ViewGroup一直向下是怎么传递的?

如果你有类似的疑问,相信我的这篇博客能给你答案。

二.首先需要明确的几点是:

1.View一般是为了显示某些内容而存在的,它也通常用来处理用户的触屏等交互事件,而ViewGroup则是做为View的容器而存在的,虽然在代码上它是View的子类,但它通常只是做为容器用来组织它的子视图布局方式。

2.我们知道android里边View层次是一种树型结构,需要明确的是一个ViewGroup它的直接子视图才算是树结构中的儿子,再往下一层就不算了,类似于进程间的父子关系。举例,FrameLayout有两个子视图,分别是LinearLayout和TextView,而 LinearLayout又有三个子视图ImageView,那么调用FrameLayout的getChildCount()方法只会返回2,而不是 5。因此以下内容中"子视图"这个术语代表着一个ViewGroup的直接子视图,它即可能是一个View类,也可能是一个ViewGroup类。

3.Activity视图的最顶层View是DecorView,它是在PhoneWindow类中通过generateDecor()方法生成的,它继承自FrameLayout,是View层次的根视图。

4.对于触屏来说有三个主要的事件:down,move,up

那么一个触屏事件到底是怎么在View层次中上向下传递的?(这里只考虑事件已经到达DecorView时的情形,事实上是ViewRootImpl 类接收到底层InputDispatch传递过来的事件,这里就不写了),ViewRootImpl在deliverPointerEvent()方法中通过调用mView.dispatchPointerEvent(event);将触屏事件传递给了DecorView,DecorView通过 dispatchTouchEvent()继续向下传递给子视图,如果子视图也是一个ViewGroup,它又会调用自己的 dispatchTouchEvent()方法向下传递,如果子视图是一个View,那么子视图的onTouchEvent()方法就会被调用,如果子视图处理了该事件,那么事件传递就中止。整个过程像是一个递归过程,理解了一个ViewGroup怎么通过dispatchTouchEvent()传递给它的子视图这一层也就理解了整个过程。

这里就不分析ViewGroup的dispatchTouchEvent()方法的代码了,直接给出我总结出来的结论,有兴趣的读者可以分析看看。

三.总结

以下情景假设一个ViewGroup有三个子视图,按index顺序为v1,v2,v3。v1也是一个ViewGroup,v2和v3都是普通的view,而且它们有一点重叠的部分。

1.ViewGroup的dispatchTouchEvent()向下分发事件给它的子视图,那么会先分发给v3调用它的onTouchEvent 方法,如果v3不处理该事件,会继续分发给v2,如果v2不处理事件,会继续分发给v1,由于v1是一个ViewGroup,则会调用它的 dispatchTouchEvent()分发给它的子视图。

2.v3不处理该事件的含义是:在down事件到达时,onTouchEvent()方法返回false,如果在接收到down事件时返回true, 则表示处理了该事件,那么不管你在接收到move和up事件的时候返回的是什么都没有关系。因此思想是:只要你愿意处理down事件,那么你必须处理接下来的其他事件。

3.v3能接收触屏事件的前提是它的显示矩形框必须在触屏的范围之内,这里显而易见的道理,否则事件会传递给v2。

4.如果v1,v2,v3都决定不处理触屏事件,那么事件最终由ViewGroup自己来处理,它的onTouchEvent()方法会被调用。

5.如果事件传递到了v1,v1是否处理取决于它的子视图,如果它的子视图有一个处理了该事件,那么就代表v1处理了事件,如果它的所有子视图都没有处理事件而且v1本身的onTouchEvent()的方法在处理down事件的时候返回false,那么才代表v1没有处理事件。

6.如果通过setOnTouchListener()设置了一个有效的监听到view中,那么事件到达时会直接调用这个监听方法而不会调用onTouchEvent(),并返回true,表示已经处理了该事件。

到这里,onTouchEvent()返回值的含义应该很明确了,那么super.onTouchEvent()返回值是什么呢?看代码也比较简单,如果一个view不是clickable的或者不是longClickable的,那么super.onTouchEvent()直接返回false,否则就进行onClick和onLongClick处理并返回true。可调用 setClickable(true),setLongClickable(true)来改变view的状态,调用 setOnClickListener()和setOnLongClickListener()也是一样的效果。

由上面结论,如果两视图是父弟关系,它们又互有重叠部分,点击该重叠部分,先处理该事件的是下标比较大的那个视图,如果这个视图不想处理事件,才让另外一个处理。

四.onInterceptTouchEvent()

ViewGroup可以调用它的onInterceptTouchEvent()方法去拦截子视图的事件,这个方法默认返回的是false表示不拦截,如果在onInterceptTouchEvent()接收到down事件时返回了true,那么接下来的down,move和up事件都会被 ViewGroup自己的onTouchEvent()方法所接收,所有的子视图都接收不到事件,而ViewGroup自己的 onInterceptTouchEvent()方法也只有down事件会被传递过去,因为都由父View来处理,所以该方法再接收到move和up事件就没有意义了,所以只会有down事件会被传递。注释中的说法:There are no touch targets and this action is not an initial down,so this view group continues to intercept touches.

如果一个子视图决定处理全部三个事件,那么每次事件到来时都会先调用父view的onInterceptTouchEvent()方法,如果在某个事件上返回了true,那么就会拦截到该事件以及随后的事件到ViewGroup自己的onTouchEvent()方法处理,子视图会接收到 ACTION_CANCEL事件。

举例:如果子视图处理了down事件,但是ViewGroup在move到来时拦截住了move事件,那么子视图就收不到接下来的move和up事件,会收到ACTION_CANCEL事件,而ViewGroup则会接收move和up事件,onInterceptTouchEvent()方法也只会接收到down和move事件。

拦截方法有时非常有用,例如ScrollView它会先把down事件交给子视图处理,如果是点击事件,就交给子视图,如果判断出来正在拖动子视图,那么会拦截住move事件,交由自己处理,调用overScrollBy()产生滚动。

当然如果自己重写了ViewGroup的dispatchTouchEvent()方法就自己掌控了事件的分发过程,和上面的流程就不一定一样了。

总结完了,相信开头的所有问题都有了答案,有点绕人,理清了就明白了。

转载自:http://www.bdqn.cn/news/201312/12158.shtml

时间: 2024-10-12 19:11:51

Android Touch事件的分发过程的相关文章

Android touch 事件的分发和消费机制

Android 中与 Touch 事件相关的方法包括:dispatchTouchEvent(MotionEvent ev).onInterceptTouchEvent(MotionEvent ev).onTouchEvent(MotionEvent ev):能够响应这些方法的控件包括:ViewGroup.View.Activity.方法与控件的对应关系如下表所示: Touch 事件相关方法   方法功能    ViewGroup           View             Activi

Android Touch事件分发过程

虽然网络上已经有非常多关于这个话题的优秀文章了,但还是写了这篇文章,主要还是为了加强自己的记忆吧,自己过一遍总比看别人的分析要深刻得多.那就走起吧. 简单演示样例 先看一个演示样例 : 布局文件 : <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id=&q

android点击事件的分发过程

转载请注明出处 http://blog.csdn.net/a992036795/article/details/51698023 本文将讲述android点击事件的分发过程 我的上一篇文章讲述了android点击事件的来源,本文接着讲述当点击事件传输到Activity之后 分发的过程是什么样的. 上一篇文章链接: http://blog.csdn.net/a992036795/article/details/51690303 通过上一篇文章我们知道,事件最终会通过activity分发到Phone

Android Touch事件分发详解

Android Touch事件分发详解 先说一些基本的知识,方便后面分析源码时能更好理解. - 所有Touch事件都被封装成MotionEvent对象,包括Touch的位置.历史记录.第几个手指等. 事件类型分为ACTION_DOWN,ACTION_UP,ACTION_MOVE,ACTION_POINTER_DOWN,ACTION_POINTER_UP,ACTION_CANCEL, 每个 一个完整的事件以ACTION_DOWN开始ACTION_UP结束,并且ACTION_CANCEL只能由代码引

Android Touch事件传递机制详解 上

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/37961997 最近总是遇到关于Android Touch事件的问题,如:滑动冲突的问题,以前也花时间学习过Android Touch事件的传递机制,可以每次用起来的时候总是忘记了,索性自己总结一下写篇文章避免以后忘记了,其实网上关于Touch事件的传递的文章真的很多,但是很少有系统性的,都是写了一个简单的demo运行了一下,对于我们了解Android Touch事件基本上没有任何帮助. 今

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

转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在我想使用一个demo以及一个实例来学习一下Andorid中的Touch事件处理过程. 在Android系统中,和Touch事件分发和处理紧密相关的三个函数如下:(1) public boolean dispatchTouchEvent(MotionEvent ev)(2) public boolea

Android Touch事件传递机制详解 下

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yuanzeyao2008/7660997 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在我想使用一个demo以及一个实例来学习一下Andorid中的Touch事件处理过程. 在Android系统中,和Touch事件分发和处理紧密相关的三个函数如下:(1) public

Android Touch事件传递机制全面解析(从WMS到View树)

转眼间近一年没更新博客了,工作一忙起来.非常难有时间来写博客了,因为如今也在从事Android开发相关的工作,因此以后的博文也会很多其它地专注于这一块. 这篇文章准备从源代码层面为大家带来Touch事件的传递机制.我这里分析的源代码时Android4.4的. 说到分析源代码,光看肯定是不行的,一定要亲自去跟,而且要边跟边思考,所以在下一篇中.会有一个Demo来为大家详细分析源代码的走向. 以下进入正题,先来看下Android中事件的分类: 1.键盘事件:主要是指按下虚拟键盘的某个按键.或者机身的

Android touch 事件传递机制

前言: (1)在自定义view的时候经常会遇到事件拦截处理,比如在侧滑菜单的时候,我们希望在侧滑菜单里面有listview控件,但是我们希望既能左右滑动又能上下滑动,这个时候就需要对触摸的touch事件进行拦截.这个时候我们就需要明白android touch 事件传递机制, (2)以前很多时候比较模糊,也许是网上看到也有很多事件传递的相关文章,但我看着头晕,解释不彻底,有的说得一半,总算不满足不满意,于是据我自己的理解来彻底的来整理下具体的是怎么个传递方式,分享给大家,希望大家看到有什么不对的