记住的核心的三个方法:
- 事件分发
boolean dispatchTouchEvent()
- 事件拦截
boolean onInterceptTouchEvent()
- 事件消费
boolean onTouchEvent()
Activity、ViewGroup和View三者,只有Activity和View没有事件拦截。
ViewGroup事件分发机制伪代码:
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean result = false; // 默认状态为没有消费过
if (!onInterceptTouchEvent(ev)) { // 如果没有拦截交给子View
result = child.dispatchTouchEvent(ev);
}
if (!result) { // 如果事件没有被消费,询问自身onTouchEvent
result = onTouchEvent(ev);
}
return result;
}
示例代码:
MotionEventViewGroupA
public class MotionEventViewGroupA extends RelativeLayout {
//折叠构造器代码
....
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("TAG", "MotionEventViewGroupA: dispatchTouchEvent");
boolean isDispatchTouchEvent = super.dispatchTouchEvent(ev);
Log.e("TAG", "MotionEventViewGroupA: dispatchTouchEvent:" + isDispatchTouchEvent);
return isDispatchTouchEvent;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("TAG", "MotionEventViewGroupA: onInterceptTouchEvent");
boolean isInterceptTouchEvent = super.onInterceptTouchEvent(ev);
Log.e("TAG", "MotionEventViewGroupA: onInterceptTouchEvent : " + isInterceptTouchEvent);
return isInterceptTouchEvent;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("TAG", "MotionEventViewGroupA: onTouchEvent");
boolean isOnTOuchEvent = super.onTouchEvent(event);
Log.e("TAG", "MotionEventViewGroupA: onTouchEvent : " + isOnTOuchEvent);
return isOnTOuchEvent;
}
}
MotionEventViewGroupB
public class MotionEventViewGroupB extends RelativeLayout {
//折叠构造器代码
....
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("TAG", "MotionEventViewGroupB: dispatchTouchEvent");
boolean isDispatchTouchEvent = super.dispatchTouchEvent(ev);
Log.e("TAG", "MotionEventViewGroupB: dispatchTouchEvent:" + isDispatchTouchEvent);
return isDispatchTouchEvent;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("TAG", "MotionEventViewGroupB: onInterceptTouchEvent");
boolean isInterceptTouchEvent = super.onInterceptTouchEvent(ev);
Log.e("TAG", "MotionEventViewGroupB: onInterceptTouchEvent : " + isInterceptTouchEvent);
return isInterceptTouchEvent;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("TAG", "MotionEventViewGroupB: onTouchEvent");
boolean isOnTOuchEvent = super.onTouchEvent(event);
Log.e("TAG", "MotionEventViewGroupB: onTouchEvent : " + isOnTOuchEvent);
return isOnTOuchEvent;
}
}
MotionEventViewC
public class MotionEventViewC extends View {
//折叠构造器代码
....
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("TAG", "MotionEventViewC: dispatchTouchEvent");
boolean isDispatchTouchEvent = super.dispatchTouchEvent(ev);
Log.e("TAG", "MotionEventViewC: dispatchTouchEvent:" + isDispatchTouchEvent);
return isDispatchTouchEvent;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("TAG", "MotionEventViewC: onTouchEvent");
boolean isOnTOuchEvent = super.onTouchEvent(event);
Log.e("TAG", "MotionEventViewC: onTouchEvent : " + isOnTOuchEvent);
return isOnTOuchEvent;
}
}
布局文件:
当点击ViewC的时候打印:
MotionEventViewGroupA: dispatchTouchEvent
MotionEventViewGroupA: onInterceptTouchEvent
MotionEventViewGroupA: onInterceptTouchEvent : false
MotionEventViewGroupB: dispatchTouchEvent
MotionEventViewGroupB: onInterceptTouchEvent
MotionEventViewGroupB: onInterceptTouchEvent : false
MotionEventViewC: dispatchTouchEvent
MotionEventViewC: onTouchEvent
MotionEventViewC: onTouchEvent : false
MotionEventViewC: dispatchTouchEvent:false
MotionEventViewGroupB: onTouchEvent
MotionEventViewGroupB: onTouchEvent : false
MotionEventViewGroupB: dispatchTouchEvent:false
MotionEventViewGroupA: onTouchEvent
MotionEventViewGroupA: onTouchEvent : false
MotionEventViewGroupA: dispatchTouchEvent:false
分析下ViewGroup和View的事件分发的顺序:
发生触摸事件的时候,最外层的View
会先收到事件,此时最外层ViewGroupA
的dispatchTouchEvent
被调用,
dispatchTouchEvent方法中调用本身的onInterceptTouchEvent
方法。
判断onInterceptTouchEvent
的返回值,如果,为true
则表示自身拦截事件,会调用自身的onTouchEvent
方法。
并且根据onTouchEvent
返回值判断事件是否消费,并且将返回值传递给dispatchTouchEvent
返回。
如果onTouchEvent
返回值为true则事件消费,否则事件未消费,并且分发失败,往上一级View传递false。
为false
则自身不拦截事件,并且遍历自身的View,知道最后一级View。
Summary:
只有最后onTouchEvent
返回true才消费了事件。父View拦截并消费了事件,则不会再分发给子View。
PS:从网上看到很多关于事件分发机制介绍很好写的很好的,这篇笔记只是简单整理下自己的思路,具体大家可以了解下以下文章。这篇笔记也来自这些:
http://www.gcssloop.com/customview/dispatch-touchevent-theory
http://wuxiaolong.me/2015/12/19/MotionEvent/