版权声明:本文为openXu原创文章【openXu的博客】,未经博主允许不得以任何形式转载
在平时的工作中,事件分发机制是非常重要的,之前虽然说比较了解,出现问题也能得到解决,但是一直没有系统的总结一下,有些地方也不能一句话说死,今天得空简单的总结记录如下:
相关类及方法
重要方法的作用
**dispatchTouchEvent():**此方法是View中定义的,ViewGroup重写了它。View中dispatchTouchEvent()将事件交给OnTouchListener处理,并调用onTouchEvent(),这些都是让控件自己处理事件;而ViewGroup中dispatchTouchEvent()是将事件分发给他的子控件处理,如果子控件没有消费掉事件,然后再自己处理,自己处理的方式跟View中一样(最后调用的是super.dispatchTouchEvent() )
onInterceptTouchEvent(ev): ViewGroup的方法,是否拦截事件,如果返回true,则子控件无法获得事件
setOnTouchListener(): View中的方法,设置Touch监听,回调onTouch()方法
onTouchEvent(): View中的方法,解析处理事件
setOnClickListener(): View中的方法,设置点击事件,回调onClick()方法
方法调用图
分析
Android事件的传递是从外层控件传递到内层控件(父控件传子控件)的,屏幕收到事件后首先传递给最外层的容器,调用它的dispatchTouchEvent()
方法,dispatchTouchEvent()是View中的方法,ViewGroup重写了它。
ViewGroup的dispatchTouchEvent()
首先判断事件拦截是否被禁用掉了(通过disallowIntercept,此值默认是false,可以通过requestDisallowInterceptTouchEvent()
设置),如果没被禁用,则会调用onInterceptTouchEvent()
判断事件是否被拦截。如果外层控件的onInterceptTouchEvent()返回true,事件则不会继续往下传递,如果返回false(和不禁用一样)则事件不会被拦截,会遍历它的子控件,判断触摸点是否在子控件范围内。
①、如果在,就会调用子控件的dispatchTouchEvent(),子控件如果是容器又会重复上面步骤,如果不是容器,就会执行View的dispatchTouchEvent(),下面插播View的dispatchTouchEvent()分析:
View对dispatchTouchEvent()的实现判断控件是否可用(enable)&& 是否设置了OnTouchListener,如果为true会调用监听的onTouch(),onTouch()如果返回false,说明事件没有被消费掉,会继续调用onTouchEvent()
方法。
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
**onTouchEvent():**该方法会解析一系列的ACTION_DOWN,ACTION_MOVE,ACTION_UP等事件(按下、滑动、抬起等),在ACTION_UP时会调用performClick()
方法,该方法判断有没有setOnClickListener,如果设置了就会回调onClick()
方法。这个方法也有返回值,如果在某个action返回了false,则后面就不会再执行该方法了(收不到事件了)。
如果子控件可点击或者需要接受事件,onTouchEvent()一定会返回true,这样在ViewGroup的dispatchTouchEvent()中收到子控件的返回值后也继续返回true,事件到此终止。
②、如果不在任何子控件范围内(点击空白处),或者子控件没有处理掉事件(dispatchTouchEvent()返回false),则ViewGroup的dispatchTouchEvent()
会继续往下执行调用super.dispatchTouchEvent()
(View中的dispatchTouchEvent()),这也就是ViewGroup自己处理事件。