天天看点

android触摸消息处理和传递:onInterceptTouchEvent与onTouchEvent

大三了,正在找实习和准备考研中挣扎,但每天也要抽出两个小时来看看android写写代码,不知不觉已经接触android两个月了,完全是凭兴趣在网上找各位大牛的博文学的。不过有些东西直接找还是找不到,或是找到了但没有完全解答疑惑。

其中之一就是android的触摸消息机制。

想要自己实现一个侧面滑动菜单,为此需要写一个继承自LinearLayout的类作为侧滑菜单栏,要在这个类中完成对手势的判断,必须要使用户的触摸操作被该类的onTouchEvent接收到。

于是希望用类似下面的布局开始:

<LinearLayout> <!--顶层容器-->

<LinearLayout><!--作为侧滑菜单-->

...

</LinearLayout>

<FrameLayout><!--作为程序界面-->

...

</FrameLayout>

</LinearLayout>

这是就想到一个问题:作为触摸事件的MotionEvent是如何在各个视图层级间传递的?

参考网上资料,有如下结论:

1、对于所有的ViewGroup如LinearLayout,都有两个和触摸事件有关的以MotionEvent作为参数的方法,分别是:

①.public boolean onInterceptTouchEvent(MotionEvent ev)

该方法返回一个boolean值,返回true则该ViewGroup的所有子View皆无法收到MotionEvent,返回false则该ViewGroup的和触摸位置对应的子View将收到该MotionEvent事件,并使用onTouchEvent(MotionEvent event)方法处理该事件。

就是说,如果你想在LinearLayout中捕获触摸事件并完全地处理它,那么你应该令该方法返回true。该方法默认返回false,因为一般触摸事件如点击都是由布局中的各个View处理的。

最后,需要注意的是,无论该方法返回值是true还是false,onTouchEvent都会在之后被调用。区别是:若返回false,MotionEvent事件将首先由子View(或者ViewGroup)处理,随后再传递给该ViewGroup的onTouchEvent;而若返回true,则子类不会收到MotionEvent事件,该事件直接由ViewGroup的onTouchEvent处理。

②.public boolean onTouchEvent(MotionEvent event)

该方法返回一个boolean值,返回true则表示该方法将要完全处理它,因此MotionEvent event将由接下来的默认onTouchEvent继续处理(单个手指触摸默认的流程是:ACTION_DOWN->ACTION_MOVE->ACTION_UP),并且该MotionEvent消息的传递过程在此终止。没错,终止,这就是说,其上一层的GroupView的onTouchEvent方法也无法继续处理该MotionEvent。终止之后,MotionEvent再也不会被除了返回true的onTouchEvent外的其他方法收到。具体意思可以参考实例,将TestLinearLayout2的ACTION_DOWN返回值改变一下,观察消息处理流程。而返回fase则表示该方法不会处理它,onTouchEvent的处理流程结束,MotionEvent将被传递给下一个可能能够处理它的View或ViewGroup。

总结一下:以单点触摸为例,onTouchEvent方法首先收到的一定是ACTION_DOWN事件,如果这时候返回true,onTouchEvent才会收到接下来的move和up事件并在up事件处理完后终止触摸事件的传递,否则如果返回的是false,android认为这个方法不关心触摸操作,所以onTouchEvent方法不会收到接下来的move和up事件,触摸消息直接传递下去了。

2、对于所有的View,仅有方法:

public boolean onTouchEvent(MotionEvent event)

很好理解,MotionEvent触摸事件的传递是从上至下的,而View是视图的最底层,无法将MotionEvent事件继续向下传递,因此当然不需要判断是否需要传递。

该方法返回值意义同上。

用win7自带画图(真难用。。)乱画了一张图,表示触摸事件MotionEvent的传递、处理流程,希望能帮助理解:

android触摸消息处理和传递:onInterceptTouchEvent与onTouchEvent

理解了上面的内容后,多加思考便可理解如何制作滑动菜单栏。

由于手指在界面上任何地方划过,都要求根ViewGroup下面的作为菜单容器的LinearLayout能够接收到触摸事件,因此该LinearLayout必须与ViewGroup完全重合,并用scrollBy方法将其显示内容先挪至界面之外;而同时又有一个主界面,该界面也应该是与ViewGroup完全重合的。那么,ViewGroup显然只能用FrameLayout。

一会把例子放上来,eclipse adt工程。第一次自己写东西,不知道有没有把事情说清楚,希望对大家有帮助。

http://download.csdn.net/detail/u011249211/7630939

今天太晚了,一会看世界杯决赛,明天继续写菜单的响应滑动事件,弹出和收回的实现。

滑动菜单栏,已完成:

http://blog.csdn.net/u011249211/article/details/37771527

继续阅读