android触摸事件处理流程

于 2014年03月15日 发布在 android开发 跳到评论

(系列文章点这里)

最近在工作中,经常需要处理触摸事件,但是有时候会出现一些奇怪的bug,比如有时候会检测不到ACTION_MOVE和ACTION_UP,我决定下决心写个测试的小程序,来研究一个触摸事件从上往下是怎么传递和处理的。

先说下大概的流程吧,这个应该在很多博客中都有讲解:当一个事件来临的时候,会先传递给最外层的ViewGroup(比如LinearLayout,FrameLayout),如果这个ViewGroup没有去拦截这个事件的话,才会给传递给下层的ViewGroup或者View。如果被拦截掉的话,它会自己去处理这个事件,这个ViewGroup内的View将无法得知上层发生了什么。

ViewGroup的拦截事件的函数为

public boolean onInterceptTouchEvent(MotionEvent ev)

onInterceptTouchEvent的参数ev就是一个触摸事件,可以从ev获取到事件的坐标,类型,当前屏幕上点的个数等等。通常我们在继承ViewGroup的时候都会重写这个方法,判断目前需不需要拦截,即返回true还是false。返回true的时候表明事件不再往下传了,否则就往下传。那返回true的时候怎么处理呢?

这就需要onTouchEvent():

public boolean onTouchEvent(MotionEvent ev)

具体怎么实现就根据实际的需要来了。我们发现他的返回值也是boolean,那返回true或者false的时候会有什么影响呢?用一张图来说明:

触摸流程,全是FALSE

这个一个典型的流程,也就是所有的相关方法都返回false的时候,一个事件先到了LinearLayout,它不拦截,然后就往下面跑,到了FrameLayout上,他又不处理,又传到了Button上,这个时候Button返回了false,然后这个事件往上传,最后没有人处理。当FrameLayout的两个方法返回true的时候会怎样呢?

FrameLayout返回true

FrameLayout的onInterceptTouchEvent返回true后,就拦截触摸消息了,然后交给自己的onTouchEvent处理。这里面的逻辑自己定义就好了,如果这个事件被消费掉了,返回true就可以了,这样系统就不会接着传了,事件处理到此为止。

是不是按下,移动,松开的流程都是按照这样处理的呢?答案是否定的。ACTION_DOWN事件的判断和处理,直接影响到了后续的ACTION_MOVE和ACTION_UP,在上面的图中,FrameLayout的onTouchEvent返回了true,那么当ACTION_MOVE来到FrameLayout这一层的时候,就不再需要通过onInterceptTouchEvent拦截了,直接用onTouchEvent处理。如果说一个ACTION_DOWN从头到尾都是返回false,那么后续的ACTION_MOVE和ACTION_UP就没法被感知到了。

下面说一下多点触摸的情况:

多点触摸的时候,会多两个事件 ACTION_POINTER_UP和ACTION_POINTER_DOWN。当第一个手指按下的时候,会产生ACTION_DOWN,当第二个手指按下的时候,会产生ACTION_POINTER_DOWN,第三个或者更多手指按下的时候,也是ACTION_POINTER_DOWN,如果此时有一个手指离开屏幕,会产生ACTION_POINTER_UP,当最后一个手指离开屏幕的时候,才会产生ACTION_UP。在整个操作过程中,一个触点会始终保持一个固定的ID,方便记录和处理,比如说在ACTION_MOVE的处理过程中,可以通过MotionEvent的getX(int pointerIndex)来获取某个点的坐标。

 

前两天看到一篇文章,对触摸事件解释的更详细了,比如说OnLongClickListener和OnClickListener的工作原理等等。如果你都能理解了,那么Android的触摸控制也就可以轻松搞定了。

http://hunankeda110.iteye.com/blog/1944311

本文共有 14条评论 | 沙发:文章评论

  1. wm说道:

    这么好的文章怎么没有评论呢~ 顶一个

  2. […] 先说下这个滑动的过程吧。如果你还不熟悉android的触摸事件控制流程,点击这里。然后打开eclipse一步一步跟踪代码。 首先看onInterceptTouchEvent方法,ACTION_DOWN事件下来之后,他会记录下当前坐标,相对于父亲的坐标等等,然后判断下是否还在滑动状态,如果没有的话,把mTouchState置为TOUCH_STATE_REST,所代表的意思是桌面现在还是静止的状态。然后onInterceptTouchEvent会返回false。为什么会返回false呢,为什么不直接返回true进行拦截呢?一是因为如果拦截掉了的话,就不会响应图标的点击事件了,二是滑动并不是从ACTION_DOWN开始的,而是滑动一段距离之后开始的,你可以在你的桌面上试一试,你的手指滑动了一段距离之后图标才开始移动。 […]

  3. 采薇说道:

    总结得很好

  4. John说道:

    ACTION_DOWN时间的判断和处理 ——> ACTION_DOWN事件的判断和处理

  5. 贝壳说道:

    图很清晰呀!第二张图中,如果onTouchEvent返回false,是不是就直接向上面去了而不会到button了?

  6. 其实-我不懂说道:

    这么好的文章怎么没有评论呢~ 顶一个

  7. 无敌小包哥说道:

    赞一个 这两个小图画得特别好, 一图顶千言万语

  8. K说道:

    画的图太赞了,秒懂

  9. 侯永奇说道:

    很好。继续顶!

留下评论!

:wink: :twisted: :roll: :oops: :mrgreen: :lol: :idea: :evil: :cry: :arrow: :?: :-| :-x :-o :-P :-D :-? :) :( :!: 8-O 8)