事件分发机制的目的是:只让一个View拥有控制事件的权力,并找出这个View记录再将权力分发给它。
1.dispatchTouchEvent 用来进行事件分发.
如果事件能够传递给当前View,那么此方法一定会被调用。
返回结果受当前View的OnTouchEvent和child的disPatchTouchEvent控制。表示是否消耗
public boolean dispatchTouchEvent(MotionEvent ev);
单纯的返回boolean结果没有意义,其中的IntercepterTouchEvent,onTouchEvent都会在super.dispatchTouchEvent()中调用;
2.onInterceptTouchEvent
会在dispatchTouchEvent中调用
用来判断是否需要拦截某个事件
在同一个事件序列中,此方法只会被调用一次
返回结果表示是否拦截当前事件
仅ViewGroup有此方法,View没有,只要传到View的dispatchTouchEvent事件,那么便会走OnTouchvent方法
public boolean interceptTouchEvent(MotionEvent ev);
3.onTochEvent
这个方法返回的true和false并不意味着让当前View使用这个方法,
只是说这个View类要获得事件的权力,让IntercepterTouthEvent(ViewGroup中,View没有这个方法)以后把事件权力都给我
public boolean onTochEvent(MotionEvent ev);
//这便是精髓
dispatchTouchEvent(){
boolean result=false;
if(intercepterTouch()){
result = OnTouchEvent();
return result;
}else{
result = children.dispatchTouchEvent();
return result;
}
}
***有些人总是自己用logd测试出child类的OnTouchEvent方法会比parent类的dispatchTouchEvent先打印,
Log.d(TAG, "dispatchTouchEvent: "+super.dispatchTouchEvent(ev));
那是因为你打印之前先执行了super.dispatchTouchEvent(),
所以会调用上面这段精髓代码,而且intercepterTouch()默认返回false
parent.dispatchTouchEvent()方法中会调用-->
parent.intercepter()-->返回false 使得在dispatch()接着调用children.dispatchTouchEvent()
如果children也是ViewGroup,那么会循环继续调用到他的children,一直到View的dispatch()
而View没有Intercepter,所以直接调用OnTouchEvent,所以你看到了children的OnTouchEvent先打印
以上一段你会发现,一切都是在parent类的dispatchTouchEvent()内部执行的。
***那么现在再理一理,在不拦截(不返回true,在interceptTouchEvent()中),事件顺序:
parent.dispatchTouchEvent()-->parent.intercepterTouch()返回false-->
child.dispatchTouchEvent()-->child.intercepterTouch()返回false-->
…………………………
当child为View时,child.dispatchTouchEvent()-->child.onTouchEvent()-->
child.onTouchEvent()返回的boolean类型如果是false,那么parent类的dispatchTouchEvent方法会调用super.dispatchTouchEvent()(源码中有),
<这个是自己分析的>也就是View中的方法,View中没有Intercepter,那么会直接调用onTouchEvent方法,这个也就是parent的OnTouchEvent()<这个是自己分析的/>,
所以如果child类中onTouch返回为false,那么会一直往parent的onTouch中跑,直到某层返回true,此时不仅调用,并且**记录**
同一个事件序列中便不会再次调用本层的IntercepterTouchEvent(),而是直接intercepter=true,
此时拦截并执行本层的onTouch,现在就不会走child中的dis和tou了.直到下一个事件序列的down事件
下面放源码: 关于 **记录**
final boolean intercepted;
// 当交由Child处理时 mFirstTouchTarget != null
//当不是down事件,并且不给child处理时,intercepted = true;
//就是说当强行拦截,上面说的记录便是指的这个 mFirstTouchTarget;赋值过程在后面addTouchTarget();
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
//FLAG_DISALLOW_INTERCEPT 这个子类可以设置,用来要求不拦截,除了Down事件,大家肯定用过。
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
下面放源码: 关于 如果child类中onTouch返回为false,那么会一直往parent的onTouch中跑
if (child == null) {
//View的dis方法,没有Inter,会直接OnTouch
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
其中的 handled = child.dispatchTouchEvent(event),如果返回true也就是说children要事件,
那么会给mFirstTouchTarget赋值: 进行标记
private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
target.next = mFirstTouchTarget;
mFirstTouchTarget = target;
return target;
}