事件分发
- 事件
用户通过屏幕与手机交互时,每次点击、长按、移动等都是一个事件。 - 事件分发
某一个事件从屏幕传递到各个View,由View来消费事件或者忽略这一事件的过程。
事件分发的对象
- 系统把事件封装为MotionEvent对象,事件分发的过程就是MotionEvent分发的过程。
- 事件类型:
按下(ACTION_DOWN)
移动(ACTION_MOVE)
抬起(ACTION_UP)
取消(ACTION_CANCEL)
事件序列
- 从手指按下屏幕开始,到手指离开屏幕所产生的一系列事件。
- 同一事件序列,如果子View(ViewGroup)没有处理该事件(没有消费事件),那么后续事件就不会再传递到子View中。如果没有任何子View处理,就会交给Activity的onTouchEvent处理。
传递层级
- Activity→Window→DecorView→ViewGroup→View
如果没有被消费,则一层层的向上传递到Activity(通过每层的onTouchEvent方法)
Activity事件分发
//1.开始
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
//空方法,可以重写这个方法来监听事件的开始
onUserInteraction();
}
//会跳转到第3点
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
//2.Window是一个抽象类,只有一个子类PhoneWindow(窗口),PhoneWindow内部有个DecorView
public class PhoneWindow extends Window implements MenuBuilder.Callback {
...
private DecorView mDecor;
//3.
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
}
//4.DecorView继承自FrameLayout,它是Activity下的最顶层View,我们setContentView(R.layout.activity_test);的时候就是设置到这个DecorView中的
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
...
//5.在DecorView中superDispatchTouchEvent方法,进入到ViewGroup中的dispatchTouchEvent
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
}
//6.这个是ViewGroup中的
public boolean dispatchTouchEvent(MotionEvent ev) {
...
}
ViewGroup事件分发
ViewGroup:dispatchTouchEvent
- 0.判断安全策略,判断一个ViewGroup不处于视图的顶部
- 1.去判断是否需要拦截事件(可以重写onInterceptTouchEvent,返回true来拦截ViewGroup中的事件)
- 2.在当前ViewGroup中找到用户真正点击的View
- 3.分发事件到该View上
ViewGroup中事件透传
- 判断是否是滑动事件,如果是,则额外处理滑动事件,然后继续向下分发事件
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//判断是否滑动事件
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
down_y = (int) ev.getRawY();
break;
case MotionEvent.ACTION_UP:
if (Math.abs(ev.getRawY() - down_y) > 10){
if (onDispatchTouchListener != null) {
onDispatchTouchListener.dispatchTouchEvent();
}
}
break;
}
return super.dispatchTouchEvent(ev);
}
ViewGroup中事件拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//onInterceptTouchEvent中返回true则会拦截事件,停止向下传递
return true;
}
View事件分发
//1.dispatchTouchEvent
//2.onTouchEvent
public boolean dispatchTouchEvent(MotionEvent event) {
...
//判断安全策略
if (onFilterTouchEventForSecurity(event)) {
//鼠标滚动条拖动
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//已注册TouchListener,监听onTouch()返回值
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
//最终传递给onTouchEvent
if (!result && onTouchEvent(event)) {
result = true;
}
}
...
}