定义:事件分发,以点击事件为例,即当一个MotionEvent产生,到系统将这个事件传递给一个具体的 View 的过程,就是分发的过程。
主要包括三个重要的方法:dispatchTouchEvent、onInterceptTouch、onTouchEvent
fun dispatchTouchEvent(ev: MotionEvent?):Boolean:用来进行事件分发,如果事件能够传递给当前 View ,那么该方法一定会被调用,返回结果受当前 View 的 onTouchEvent 和下级 View的 dispatchTouchEvent 影响,返回是否消耗当前事件。
fun onInterceptTouch(ev:MotionEvent?):Boolean:在 dispatchTouchEvent 方法内部调用,用来判断是否拦截某个事件,(默认如果拦截,那么同一个事件序列当中,在拦截以后的事件,将不会被调用。
备注 :同一个事件序列包括 ACTION_DOWN + n 个 ACTION_MOVE + ACTION_UP
fun onTouchEvent(ev:MotionEvent?):Boolean 在 dispatchTouchEvent 方法内部调用,用来处理点击事件,如果不消耗,同一个事件序列中,当前 View 无法接收后续事件。
备注 :注意都是在同一个事件序列中,当下一次点击,有新的事件序列是,会继续被调用。
以上三个方法当结构关系如下:
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
consume = onTouchEvent(ev);
} else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
其中 view 的 onTouchListener 响应高于 onTouchEvent,其中 onClickListener 在 onTouchEvent 中回调,所以,如果 View 设置类onTouchListener 则不会响应 onClickListener。
详细图讲解:
事件分发顺序:Activity -> Window -> View
首先,Activity,如果它自己将事件消耗,就不会有后面什么事儿了。
然后,如果可以传递给 ViewGroup,则它会走上面的黑体加粗的三个 fun 方法,经过 dispatchTouchEvent 方法,如果拦截事件,则受自身的 onTouchEvent 影响,如果不拦截事件,受子元素的 dispatchTouchEvent 影响,所以,他会有左右两个出口,自身 onTouchEvent 返回 false ,则该事件会向上传递给 父元素的 onTouchEvent,最终到Activity。或者向下传递给子元素的 dispatchTouchEvent ,又开始新一轮的循环。
最终,传递给 View , 由于 View 没有 onInterceptTouchEvent ,所以它只能走 onTouchEvent ,如果不消耗,就继续向上传递,或者直接在分发的时候 return true,消耗事件。
以上就是View的事件分发的详细流程。
事件传递的结论
- 同一个事件序列,是指从手指接触屏幕,到离开屏幕这个过程所产生的一系列事件,即 ACTION_DOWN + n 个 ACTION_MOVE + ACTION_UP。
- 正常情况,一个事件序列,只能被一个View拦截且消耗。但,View 也可以在 OntouchEvent 中强行传递给别但 View 进行处理。
- 当 onInterceptTouchEvent 返回 true,则这个事件序列中剩余当事件都由它来处理,并且剩余当事件也不会再调用onInterceptTouch。
- 如果 onTouchEvent 的 ACTION_DOWN 返回 false ,则同一事件序列会交由父元素处理。
- 如果 onTouchEvent 只消耗 ACTION_DOWN,则同一事件序列其他事件最终会传递给Activity。
- ViewGroup 的 OnInterceptTouchEvent 默认返回 false。
- View 没有 OnInterceptTouchEvent,所以有方法传递给它,默认执行 onTouchEvent。
- View 的 OnTouchEvent 默认返回 true,除非是( clickable && longClickable ) == false 其中,View 的 longClickable 默认为 false,但Clickable 像 Button 默认返回 true , TextView 默认返回 false。
- View 的enable不影响 OnTouchEvent,因为它不影响 clickable 和 longClickable属性。