前言
在Android中,View视图是以树状结构来展示的,一个ViewGroup既可以可以装入若干个View,也可以在ViewGroup里面再嵌套若干个ViewGroup,那么对于一个事件,子View或者父ViewGroup都可能要处理,因此就须有有一些“规则”来定义这个事件处理机制。
MotionEvent事件
在手指接触屏幕后所产生的一系列事件中,典型的事件类型有如下几种:
ACTION_DOWN ----- 手指刚接触屏幕
ACTION_MOVE ----- 手指在屏幕上移动
ACTION_UP ----- 手指从屏幕上松开的一瞬间
正常情况下,一次手指触碰屏幕的行为会触发一系列触摸事件,考虑如下几种情况:
点击屏幕后立即松开,事件顺序为 ACTION_DOWN -> ACTION_UP
点击屏幕后滑动一会再松开,事件顺序为 ACTION_DOWN -> ACTION_MOVE ->...-> ACTION_MOVE -> ACTION_UP
获取点击事件发生的x坐标和y坐标
getX/getY:返回的是相对于当前View左上角的x和y坐标
getRawX/getRawY:返回的是相对于手机屏幕左上角的x和y坐标
涉及到事件处理过程的有三个重要的方法
/**
* 对事件进行分发
* Activity, ViewGroup, View都有此方法
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
/**
*用来过滤事件的,即进行事件的拦截,也就是是否要向下传递事件
* 只有ViewGroup有
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
/**
* 最终用来处理事件的
*Activity, ViewGroup, View都有此方法
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
事件处置过程
当事件传递到一个ViewGroup上面时,ViewGroup会触发dispatchTouchEvent方法,随后调用onInterceptTouchEvent方法确认是否拦截此事件,最后如果事件是自己来处理的话,则调用onTouchEvent方法。
??在ViewGroup类中,onInterceptTouchEvent方法总是返回false,表示默认是不拦截事件的,除非去重写ViewGroup类来返回true。而onTouchEvent方法的返回值表示是否消费(返回true则消费)此事件,消费的意思就是说ViewGroup自己处理了这个事件,不再传递到上一层的onTouchEvent去。
??而在View中,与ViewGroup相比,同样有dispatchTouchEvent方法和onTouchEvent方法。但是没有onInterceptTouchEvent这个方法,因为在一个View中,已经是View树的叶子节点,它没有下一级的视图嵌套,所以不需要决定是否拦截事件,它自己就可以处理事件了。
??在View类中,只要该View是可以点击的,那么默认都会在onTouchEvent返回true,表示自己消费了这个事件,不再传递到上一级ViewGroup去。
注意
如果在同一个事件序列里面,如果ACTION.DOWN事件不被这个View做出消耗,则后面陆续的事件序列则不会传递到这个View来。
注意事件拦截和事件消费是两回事,事件拦截说的是不把事件发给下一级View,而事件消费说的是处理完这个事件还要不要让上一级也处理,如果消费了事件那么就不会再让上一级处理这个事件