Android中的触摸事件很常见,但是处理起来却不一定简单。
比如说,一个最简单的屏幕触摸动作:按下,滑动,抬起。这个触摸动作会触发一系列的触摸事件:ACTION_DOWN->ACTION_MOVE->...->ACTION_MOVE->ACTION_UP。而当屏幕中包含一个ViewGroup,而这个ViewGroup又包含多子view时,Android系统对触屏动作的响应是如何处理的呢?
在这之前,需要先看看下面这三个与TouchEvent密切相关的函数:
1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent
当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, 进入这个 view 的 dispatchTouchEvent函数 ,然后由 dispatchTouchEvent 进行分发。如果返回值为true ,则交给这个view的onTouchEvent处理;如果返回值为 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件。
然后,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,还是会交给它的 onTouchEvent 来处理;如果 interceptTouchEvent 返回 false ,那么就传递给子 view (在这里就是次顶层的view),由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。
后面的可以以此类推。如果事件传递到某一层的view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。
关键的就是上一段的最后一句话了,这也是最容易出现问题的地方。上文说到“接收不到下一次事件”,那什么是下一次事件呢?文章一开始就提到:一个最简单的屏幕触摸动作:按下,滑动,抬起,会触发一系列的触摸事件:ACTION_DOWN->ACTION_MOVE->...->ACTION_MOVE->ACTION_UP。如果最上面的View的onTouchEvent一直是返回false的话,那我们就只能监听到TouchEvent的ACTION_DOWN事件,而ACTION_MOVE和ACTION_UP都是无法接收到的。
这有什么用呢?在一些时候,比如说我们想要响应某一个Button,但是我们希望是手指离开屏幕时才触发相关的操作。举一个例子,比如想象下你在游戏中时,不小心按下了退出按钮;而为了避免游戏退出,你移动手指到了屏幕上的其他地方,然后手指离开屏幕。在这种情况下,如果你希望游戏仍在继续,你就必须监听TouchEvent的ACTION_UP动作来响应退出操作,而最顶层的View也必须返回True才可以,否则我们是无法接受到ACTION_UP这个事件的。同样的,如果你的应用需要用到手势,也必须返回True,因为手势本质上只是对一系列的TouchEvent事件的封装而已,需要很多后续的触摸事件。但从另一方面来说,如果你的应用只需要ACTION_DOWN这个事件,也不需要用到手势,那样可以简单地返回false;这对提高性能和降低耗能也是有一定益处的,毕竟屏幕对触摸事件很敏感,短时间内就可以出发大量的触摸事件,全部都收归到程序上进行处理并没有什么好处。
这篇文章是针对各种Android入门书籍的补充介绍,因为我发现这些书籍上对TouchEvent的说明很敷衍,但却很容易给读者(我)带来一些后面的问题,所以在此予以说明。