Android的事件分发机制
当一个或多个手指触摸屏幕时,通常有四种类型的事件:
- ACTION_DOWN:按下屏幕时发生,表示触摸事件开始,他是第一个发生的事件
- ACTION_UP:手指抬起,表示触摸事件结束
- ACTION_MOVE:手指按下屏幕,并且手指移动的距离超过了某个阈值
- ACTION_CANCLE:事件已取消(不是由于用户的行为引起)
这些信息都被包含在MotionEvent中,ACTION_DOWN和ACTION_UP只有一个,而ACTION_MOVE可能存在多个,所谓的事件分发就是队MotionEvent事件分发的过程,就是找到一个能处理MotionEvent的View,过程由Activity开始,传到ViewGroup,最终再传到View,响应过程从上到下,从子到父。
当我们点击一个按钮时,这个按钮可能被包含在ViewGroup中,事件会先从Activity中开始分发进行,如果Activity要自己处理,那么这个按钮就得不到事件信息,如果Activity是进行分发,那么接下来包裹这个按钮的ViewGroup就会得到处理,同样如果这个ViewGroup要进行拦截,那么这个按钮也得不到响应,不拦截的话最终事件会被这个按钮消费。
事件分发由三个方法控制,他们被定义在Activity、View、ViewGroup中:
- Activity:
public boolean dispatchTouchEvent(MotionEvent ev); |
- ViewGroup:
public boolean dispatchTouchEvent(MotionEvent ev); |
- View:
public boolean dispatchTouchEvent(MotionEvent ev); |
dispatchTouchEvent
它是事件分发处理函数,如果事件传递到了当前View,那么这个方法会被调用,返回结果表示是否小号当前事件,false表示允许继续分发,返回true表示该事件不再继续分发,有可能是当前View的OnTouchEvent或者是子View的dispatchTouchEvent消费了。
当发生点击操作时,会先从Activity的dispatchTouchEvent方法开始,然后依次传递给子视图,Activity的dispatchTouchEvent方法非常简单,首先判断是不是按下,如果是则调用一下onUserInteraction,然后superDispatchTouchEvent的方法经过层层调用,会传递到View或ViewGroup的dispatchTouchEvent中。
如果superDispatchTouchEvent返回true,则事件结束,表示有View已经消费了,false的话会传递给自身的onTouchEvent方法进行消费,表示所有View的onTouchEvent返回了false,没有人去处理这个时间,只能交给自己去处理。
onInterceptTouchEvent
这个方法是在dispatchTouchEvent中调用的,用来判断是否拦截当前事件,如果当前View拦截了事件,那么在后续同一个事件序列中,这个方法不会被再次调用,默认返回false,返回true表示拦截
如图:

onTouchEvent
也在dispatchTouchEvent中调用,用来处理点击事件,如果返回true,则表示当前View消耗了此事件。
注意问题
OnTouchListener的优先级高于onTouchEvent,如果OnTouchListener,onTouchEvent就不执行,反之则会调用
如果事件一直没有被消费,最后会传给Acitvity,如果Acitivity也不需要就会被抛弃
判断事件是否被消费是根据返回值,而不是根据你是否使用了事件
onTouchListener,onTouchEvent和onClick的优先级别
onTouchListener—–>onTouchEvent—>onclickView的事件分发机制实际上就是一个经典的责任链模式
责任链模式:当有多个对象均可以处理同一请求的时候,将这些对象串联成一条链,并沿着这条链传递修改请求,知道有对象处理它为止
onClick()方法是在onTouchEvent()方法中的action==ACTION_UP时才执行的,onTouch()、onTouchEvent()、onClick()三个方法的优先级依次递减
Android事件分发机制中,主要是有两个过程,一个是向下分发的过程,该过程主要调用dispatchTouchEvent(),还有一个是向上返回的过程,主要依靠onTouchEvent()方法
view事件执行顺序dispatchTouchEvent-> setOnTouchListener的onTouch->onTouchEvent,如果setOnTouchListener返回ture,后续事件onTouchEvent不再执行
onClick是在onTouchEvent(event)方法中的,所以onTouch优先于onClick执行
