一.View
1. 点击按钮的事件分发过程
(1)button的dispatchTouchEvent
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
(2)button的setOnTouchListener的onTouch
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "onTouch execute, action " + event.getAction());
return false;
}
});
(3)button的onTouchEvent
2.执行onTouchEvent(event)的条件
以下三条 有一条不满足, 那么就执行onTouchEvent. 都满足, 那么不执行onTouchEvent
(1)mOnTouchListener不为null
(2)并且view是enable的状态
(3)mOnTouchListener.onTouch(this, event)返回true
3.另外
如果view是可点击, 或者可长按的, 那么, onTouchEvent一定会返回true,
后面的MOVE,UP等一定会被执行;但如果是imageview, 它默认不可点击, 那么会返回false, 将此事件消费掉.
因为虽然在onTouch事件里返回了false,可点击view中, 系统还是会在onTouchEvent方法中帮你返回true。
就因为这个原因,才使得后续动作ACTION_UP可以得到执行。
二.ViewGroup
1.点击LinearLayout中的button的事件分发流程(1)Linear的dispatchTouchEvent ACTION_DOWN
(2)Linear的onInterceptTouchEvent ACTION_DOWN
(3)Button的dispatchTouchEvent ACTION_DOWN
(4)Button的onTouchEvent ACTION_DOWN
可以看出,想在View上触发事件,最先捕捉到事件的是View所在的ViewGroup,然后才传到view本身.
2. 详细说明
(1)ViewGroup首先捕获到DOWN事件,如果代码中不做TOUCH事件拦截(
1.当前不允许拦截,即disallowIntercept =true,
2.当前允许拦截但是不拦截,即disallowIntercept =false,但是onInterceptTouchEvent(ev)返回false ;//拦截只需返回true
3.onInterceptTouchEvent默认是不拦截的,即返回false;如果你需要拦截,只要return true就行了,这要该事件就不会往子View传递了,并且如果你在DOWN retrun true ,则DOWN,MOVE,UP子View都不会捕获事件;如果你在MOVE return true , 则子View在MOVE和UP都不会捕获事件。
原因很简单,当onInterceptTouchEvent(ev) return true的时候,会把mMotionTarget 置为null ;
),
则开始查找当前x,y是否在某个子View的区域内,如果在,则把事件分发给此view。
(2)ACTION_MOVE事件, 把ACTION_DOWN时赋值的mMotionTarget,付给target ; 直接return target.dispatchTouchEvent(ev);
总体上ACTION_MOVE在检测完是否拦截以后,直接调用了子View.dispatchTouchEvent,事件分发下去;
(3)判断当前是否是ACTION_UP
分别重置拦截标志位以及将DOWN赋值的mMotionTarget置为null,下一次DOWN还会再赋值的
最后,修改坐标系统,然后调用target.dispatchTouchEvent(ev);
3.补充说明
其实ViewGroup也是View的子类,如果没有找到能够处理该事件的子View,或者干脆就没有子View;
那么,它作为一个View,就相当于View的事件转发了~~直接super.dispatchTouchEvent(ev);
1、如果ViewGroup找到了能够处理该事件的View,则直接交给子View处理,自己的onTouchEvent不会被触发;
2、可以通过复写onInterceptTouchEvent(ev)方法,拦截子View的事件(即return true),把事件交给自己处理,则会执行自己对应的onTouchEvent方法
3、子View可以通过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup对其MOVE或者UP事件进行拦截;