一、事件分发机制的基本概念
事件分发机制是指在Android系统中,当用户对屏幕上的控件进行触摸操作时,系统会依次把事件传递给控件树上的每个View控件,直到有一个控件成功处理了该事件或者所有控件都未成功处理该事件。
Android的事件分发机制中涉及到三个重要的类:View、ViewGroup和 MotionEvent。View是控件的基类,ViewGroup是可以持有多个子View的View,而MotionEvent则是触摸事件类。
事件分发机制的核心是ViewGroup.dispatchTouchEvent()方法和View.onTouchEvent()方法。前者是ViewGroup分发事件的方法,后者是View处理事件的方法。
二、事件分发机制的流程
事件分发机制的流程可以描述为:当用户对屏幕进行触摸操作后,系统会把该事件交给当前活动的Window对象。Window对象收到事件后会先交给DecorView进行处理。DecorView是Window对象的根View,它是一个FrameLayout,拥有多个子View,即Activity中设置的布局文件。接着DecorView会调用dispatchTouchEvent()方法把事件传递给子View,直到有一个子View成功处理了该事件。
当ViewGroup接收到事件时,会先调用自己的onInterceptTouchEvent()方法来询问是否拦截该事件,如果该方法返回true,则表明该ViewGroup会处理该事件,否则就把该事件交给该ViewGroup的子View进行处理。如果所有的子View都不能处理该事件,则该事件继续向上层的ViewGroup传递,直到确定该事件被处理或者整个控件树中不存在可以处理该事件的View。
三、事件分发机制的代码实现
public class MyViewGroup extends ViewGroup {
public MyViewGroup(Context context) {
super(context);
}
public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 对子View进行布局
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// 进行事件分发
boolean handled = false;
if (onInterceptTouchEvent(ev)) {
handled = onTouchEvent(ev);
} else {
handled = getChildAt(0).dispatchTouchEvent(ev);
}
return handled;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 进行事件拦截
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 处理事件
return true;
}
}
四、事件分发机制的注意事项
1、onInterceptTouchEvent()方法可以拦截事件的传递,如果该方法返回true,则表明当前ViewGroup会处理该事件;
2、onTouchEvent()方法中必须要调用super.onTouchEvent()方法,否则子View将不会收到触摸事件;
3、在Activity的布局中,可以使用android:onClick=""属性来直接绑定点击事件,也可以调用View的setOnClickListener()方法来动态绑定点击事件;
4、在处理多点触摸事件时,必须使用event.getActionMasked()来获取事件类型,只有event.getAction()可能获取不到正确的事件类型。
五、事件分发机制的优化
在事件分发机制中,每个View都要进行事件的分发和处理,如果View的层级结构非常复杂,那么就会导致事件处理过程非常耗费系统资源。
针对这个问题,可以使用一些优化方式来加速事件的分发和处理,例如:
1、对于不需要接收触摸事件的View,可以设置setClickable(false)或setFocusable(false),这样可以避免不必要的事件分发;
2、在View的onTouchEvent()方法中,可以进行事件过滤,例如判断点击事件是否处于某个范围内,避免不必要的事件处理;
3、在View的onTouchEvent()方法中,可以进行手势识别,例如判断是否有左滑或右滑的动作,从而在系统底层减少事件的发送。