View 点击事件分发
当一个控件被点击时,该控件的dispatchTouchEvent方法就会被调用,由于View的子类没有重写该方法(ViewGroup等会再讨论),故该控件的类会不断往基类查找,最终点击事件的分发由View里的 dispatchTouchEvent方法开始进行。
1 | public boolean dispatchTouchEvent(MotionEvent event) { |
以上为View的dispatchTouchEvent方法的代码,dispatchTouchEvent传入一个带有点击信息的event参数,返回一个布尔值,表示这个点击事件是否已经被消费处理。代码中比较关键的是第5行的if语句:其中判断了mOnTouchListener是否为null,而mOnTouchListener顾名思义就是我们平时经常注册的touch事件监听器了
1 | public void setOnTouchListener(OnTouchListener l) { |
以上为View中的注册touch事件监听器代码。
发现touch事件监听器不为null时,View就会调用listener的onTouch方法了,如果onTouch方法返回了true,那么该方法就不会往下继续执行,dispatchTouchEvent就会返回true代表事件被消费掉了。
但如果我们没有注册touch事件监听器,或者在onTouch方法中返回了false,方法就会继续执行进入到onTouchEvent中
1 | public boolean onTouchEvent(MotionEvent event) { |
以上是View的onTouchEvent的代码。由于代码很长,我们只看关键的部分,从第9行的注释我们可以得知,如果被点击的控件是disable的,那么该方法不会执行任何动作,但如果该控件是clickable的,dispatchTouchEvent方法依然会返回true,该点击事件依然会被消费掉。
接着看到第23行,如果该控件是可点击的,那么代码就进入if语句里面,执行第60行的performClick方法
1 | public boolean performClick() { |
以上就是View中performClick方法的代码,第7行就是我们调用了再熟悉不过的onClickListener的onClick方法了。
综上所述,View的事件分发如下图所示:
ViewGroup点击事件分发
讲完了View的事件分发机制,我们再来讲讲ViewGroup的事件分发机制。ViewGroup继承自View,然而ViewGroup重写了View中的dispatchTouchEvent方法,代码如下:
1 |
|
我们依然是找关键代码来看,在第15行有一个非常关键的方法:onInterceptTouchEvent,该方法的返回值赋值给了布尔变量intercepted,而在第32行intercepted的取值决定了是否进入该if语句,而该if语句就是ViewGroup分发touchEvent给他的子View的关键所在。
ViewGroup中的onInterceptTouchEvent方法如下:
1 | /** |
注释非常长,而代码仅仅只是返回了一个false。由注释可知,该方法的作用是返回当前ViewGroup是否拦截点击的touchEvent,如果该方法返回false,则dispatchTouchEvent方法将会进入第32行的if语句,执行第54行的dispatchTransformedTouchEvent方法:
1 | private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel, |
该方法为ViewGroup的一个private方法,他的返回值表示该点击事件是否被消费掉,方法的第1个参数即是我们的点击事件,我们重点注意方法的第3个参数child,在第10行的if语句中,如果child为null,则把touchEvent交给基类处理(就是把当前ViewGroup当成一个普通的View进行事件分发处理),如果child不为null,则把touchEvent交给child(子View)来处理。
在dispatchTouchEvent的第54行我们传入了child的参数,故我们在尝试把touchEvent交给ViewGroup的子View处理。然而当onInterceptTouchEvent返回了true或子View处理点击事件失败时,我们就会执行dispatchTouchEvent方法的第71行,此时我们在此调用了dispatchTransformedTouchEvent方法,但是这次我们传入的child参数为null,故该方法会把点击事件交给ViewGroup的基类处理。
综上所述,ViewGroup的点击事件分发流程如下: