对于手机应用来说,能和屏幕进行交互是一个最基本的需求了啦!所以,在手机应用开发中“屏幕触摸事件”是很重要的一块内容,有比较深入理解一下。
屏幕触摸事件中用到一个重要的类是MotionEvent,MotionEvent中包含了屏幕所能响应的所有事件,大家可以查找API看看,有很多事件。不过最常用的的是四种事件:
MotionEvent.ACTION_CANCEL
MotionEvent.ACTION_DOWN
MotionEvent.ACTION_MOVE
MotionEvent.ACTION_UP
后三个事件都很好理解,CANCEL有点难理解,不过实际使用中,这个事件是在如下情景中触发的:当父控件Intercept某事件后,子控件就会响应到CANCEL事件。
在说onInterceptTouchEvent和onTouchEvent之前,我想说些别的。
其实对于View类,它只有dispatchTouchEvent和onTouchEvent这两个方法,我们知道ViewGroup是继承自View的,在ViewGroup类中增加了一个onInterceptTouchEvent方法,并且在ViewGroup类中重写了View的dispatchTouchEvent方法。
从功能上来说这三个方法的作用如下:
1)public boolean dispatchTouchEvent(MotionEvent ev) 这个方法用来分发TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent
但就我目前的经验来看,是实际开发中dispatchTouchEvent方法是不用太关心的,也就是说在定制控件的时候不用override它,可以当它不存在。这只是我目前肤浅的理解。
还有一点我想提一下,Activity中也有dispatchTouchEvent和onTouchEvent方法。
我们想象这样一个情况:有一个Activity,它上面的布局是:有一个LinearLayout,LinearLayout上面有一个Button。
1.当我们点击Button时,(暂且不考虑Activity),首先产生的DOWN时间,这个事件首先到达LinearLayout 的onInterceptTouchEvent方法中,如果onInterceptTouchEvent的返回值是false,表示LinearLayout不对DOWN事件进行拦截,那么DOWN事件就会传到Button的onTouchEvent方法中(注意:Button是没有onInterceptTouchEvent方法的),这时Button的onTouchEvent就会消费掉这个DOWN动作,(1)如果Button的onTouchEventEvent方法返回为true,表示Button的onTouchEvent方法还会响应到后续的MOVE、UP等一系列的动作。接受后续MOVE、UP动作也是先由LinearLayout的onInterceptTouchEvent拦截,再传向Button的onTouchEvent中。-----所有的动作都由Button来处理(2)如果Button的TouchEvent方法返回为false,表示Button的onTouchEv。ent方法不会响应到后续的MOVE、UP等动作了,而且会把DOWN动作传向LinearLayout的onTouchEvent方法中,这个时候的逻辑就和Button中的onTouchEvent一样了,return true,接受后续动作(不过需要注意的时候,后续动作就再也不会经过onInterceptTouchEvent了,而是直接进入onTouchEvent中,这一点API文档中有说明),return false,让上级(父控件或activity)的onTouchEvent进行处理。----Button只处理了DOWN动作,上级或者上上级处理了所有动作
2.当我们直接点击LinearLayout区域,而不是Button的时候,onInterceptTouchEvent之后,会直接进入LinearLayout的onTouchEvent方法中,之后的一切就和上面讲的一样了。
3.当LinearLayoutd的onInterceptTouchEvent返回true时,所有的动作都会被LinearLayout拦截下,直接交到LinearLayout的onTouchEventEvent处理。
4.还有一个动作没有说,那就是ACTION_CANCEL,上面提到的所有情况都不会出现这个动作。大家考虑这种情况,LinearLayout的onInterceptTouchEvent不拦截DOWN动作,拦截MOVE动作。这样Button的onTouchEvent就会收到ACTION_CANCEL动作,大家可以试一下。
自己写了一个demo,可以结合demo看理解更好些。
下载地址:http://download.csdn.net/detail/lizhongyisailang/5472611
再啰嗦几句,大家想想这样情况,如果你使用了一个开源代码中的一个控件,它默认是拦截动作的,这样的话子控件就响应不到动作了,这有时不是我们期望的,这是我们只需自己定制一个控件继承自那个控件,override那个控件的onInterceptTouchEvent,return false;就可以了。
可是我们的需求是这样的:让某些子控件被拦截,某些子控件不被拦截,大家知道怎么做吗?呵呵。
要想SeekBar不响应ViewPager的划屏动作,只需要在定制的SeekBar控件中的onTouchEvent()方法中,处理ACTION_DOWN动作时加入getParent().requestDisallawInterceptTouchEvent(true),处理ACTION_UP动作时加入getParent().requestDisallawInterceptTouchEvent(false),这样就可以了。