在Android系统中,触摸是用户最常用,最基础的交互方式,只有弄通触摸事件在系统中的传递处理机制才能更好地增强用户的交互体验。
由此可见,Touch事件是层层向下传递的,如果某个视图接收了此事件则接下来的视图就无法再次接收,但ViewGroup可以强制从子视图手中剥夺一个触摸事件。以下是处理触摸事件的一些要点和方法:
触摸事件从view树的根节点开始一直传递到最下层,直到某个onTouchEvent()接收处理此事件。每个部分对触摸事件的处理过程如下:
Activity的处理过程:
Activity.dispatchTouchEvent()最先被调用,其作用是调用RootView(通常是一个ViewGroup)的dispatchTouchEvent(),即负责分发事件。ViewGroup中的dispatch会调用其他孩子的dispatchTouchEvent()。注意:Activity中的onTouchEvent()是整个View的触摸事件传递链条的终点,不过前提是整个过程中没有view的touchEvent对此事件感兴趣。View的处理过程:
检查是否有TouchListener()注册在这个View中,如果有则查看其是否想要消费此次事件,如果不消费事件,那么接下来该View的onTouchEvent()就要被调用了,如果未返回true,事件就会返回视图树的上一层。ViewGroup的处理过程:
根据触摸发生的位置来判断哪些孩子可能会触发触摸事件,如果有重叠部分则按照被加入到ViewGroup中顺序的逆序来依次处理。ViewGroup可以引发一个中断(onInterceptTouchEvent())来强制把事件交给自己处理,当子视图的事件被剥夺时,子视图会收到ACTION_CANCEL事件,子视图可以用requestDisallowTouchIntercept()方法来屏蔽这个事件。由此可见,Touch事件是层层向下传递的,如果某个视图接收了此事件则接下来的视图就无法再次接收,但ViewGroup可以强制从子视图手中剥夺一个触摸事件。以下是处理触摸事件的一些要点和方法:
用户控件的触摸处理
处理触摸事件的方法:
- -给视图额外设置一个onTouchListener
- -重载onTouchEvent()事件
消费事件:
- -如果对某个触摸事件感兴趣,应对ACTION_DOWN事件返回true,即使对ACTION_DOWN事件并不关心
传递Touch事件:
- -调用目标的dispatchTouchEvent()
- -不要直接调用目标的onTouchEvent()
建议:
- -在覆盖某处理方法时,每次都调用父类的相应方法。
- -处理ACTION_MOVE时,要用slop对其进行检查。
- -记得处理ACTION_CANCEL(一般可以与ACTION_UP一致)
多点触摸建议:
- -MotionEvent.getPointerCount()可以得到当前触摸的点数。
- -ACTION_POINTER_DOWN/UP在第2根及以上的手指按下或弹起时发生。
ViewConfiguration提供的常量
getScaledTouchSlop()(获取规模化触摸面积系数):- touch slop:决定此触摸事件能否从轻触转换为拖拽。
- fling手势:手指在滑动一个列表时,在某一个速度之上时当手指离开屏幕列表不会马上停下。
Touch Delegate(触摸代理)
作用:
允许父视图来定义一个特定的触摸区域,在此触摸区域中,所接收的所有事件都会向前传递给某个孩子视图。
用法:
<span style="font-size:14px;">ViewGroup parent;
View child;
Rect touchArea;
parent.setTouchDelegate( new TouchDelegate(touchArea, child) );</span>