View事件分发机制
首先感谢郭大侠和鸿大哥的无私奉献
想看源码分析的可以直接跳到最后,有给出他们的源码分析的链接
在Activity里有一个Button,给Button添加事件如下
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "button+setOnClickListener000");
}
});
button.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
int action = event.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
Log.e(TAG, "button+onTouch ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "button+onTouch ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG, "button+onTouch ACTION_UP");
break;
default:
break;
}
return false;
}
});
然后点击按钮并轻轻滑动,会打印出button+onTouch ACTION_DOWN,button+onTouch ACTION_MOVE,button+onTouch ACTION_UP,button+setOnClickListener000
(可见onTouch方法先于onClick方法执行)
如果把onTouch()方法的返回值改为true,则会打印出button+onTouch ACTION_DOWN,button+onTouch ACTION_MOVE,button+onTouch ACTION_UP
为什么会这样呢?
你可以理解为当onTouch()返回true,就是被onTouch把事件消费掉了,事件不向后传递,所以onClick方法就不会执行了。
深入一点点分析
首先需要知道一点,只要你触摸到了任何一个控件,就一定会调用该控件的dispatchTouchEvent方法。
其实当我们触摸Button时,就会调用View的dispatchTouchEvent方法(因为Button本身没有这个方法,所以会向上面的父类一直查找,直到View)
那么View的这个方法里究竟做了什么呢?看下源码
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
首先看看第一个判断条件,mOnTouchListener
public void setOnTouchListener(OnTouchListener l) {
mOnTouchListener = l;
}
可见只要给控件添加了OnTouch方法,mOnTouchListener就不为空,第二判断条件-控件是否是enable的,按钮默认都是enable的,所以这里是true,最后会调用onTouch方法,假如返回了true,那么onTouchEvent方法就不会执行了,返回false,onTouchEvent方法才会会执行,根据之前的测试,可知onclick方法应该是在onTouchEvent里执行的了。
再来一小段截取的源码
public boolean onTouchEvent(MotionEvent event) {
...
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
...
if (!post(mPerformClick)) {
performClick();
}
}
...
return true;
}
return false;
}
2.只要(((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) 为true,最后onTouchEvent就会返回true(不论action此时为ACTION_DOWN,ACTION_MOVE还是ACTION_UP),否则返回false。
切记,只有每个ACTION_DOWN,ACTION_MOVE,ACTION_UP事件对应的dispatchTouchEvent方法都返回true,才能依次往后执行,就是说如果dispatchTouchEvent方法里此时的event.getAction()==ACTION_DOWN, 你返回了false,那么后面的dispatchTouchEvent方法都不会执行(说白了,每个动作事件都会执行一次dispatchTouchEvent,执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了,也就是ACTION_MOVE,ACTION_UP事件将不会得到执行。这个先记着,要结合后面的ViewGroup的事件分发机制一起理解)。
想要深入理解的可以看看这两位大神的源码分析
郭霖大侠
鸿洋大哥