自定义View(一):事件分发

一.touch事件分发
1.View的事件分发逻辑其实很简单,从手指触摸手机屏幕开始,系统将该事件绑定到MotionEvent对象上,从Activity的根布局DecorView开始向下进行传递。

简化后的代码逻辑为:

//当前ViewGroup处理点击事件
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean consume = false;
        //是否拦截该事件
        if (onIntercepterTouchEvent(ev)) {
            //拦截则调用onTouchEvent进行处理
            consume = onTouchEvent(ev);
        } else {
            //不拦截则当前View的子View处理该点击事件,子View\"递归判断\"
            consume = child.dispatchTouchEvent(ev);
        }
        return consume;
    }

2.ViewGroup处理touch事件:
是否拦截?
拦截:则自己处理逻辑,事件分发就此终止。
不拦截:则传递给子布局,ViewGroup是默认不拦截touch事件。如果子View还是一个ViewGroup,那么继续重复上述流程,直到最后一个布局为View。由于View没有子布局,所以View也不存在onIntercepterTouchEvent拦截函数

二.Activity的onTouchEvent(),View的onTouch(),View的onTouchEvent()之间是什么关系?
1.Activity的onTouchEvent()
根据代码的追踪,Activity的onTouchEvent(),最终是在根布局DecorView中进行处理,

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        final Window.Callback cb = mWindow.getCallback();
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }

当mFeatureId < 0的时候,执行activity的onTouchEvent()函数,否则,执行DecorView的dispatchTouchEvent()函数,也就是上面写的“事件分发”流程。 mFeatureId < 0是什么意思?源码注释中解释到:

/** The feature ID of the panel, or -1 if this is the application's DecorView */
当mFeatureId < 0的时候表示该panel容器是Actvity/Dialog本身只有DecorView布局没有额外的子布局

也就是说:
当touch事件是分发给只含有DecorView布局的Activity本身,则直接执行Activity的onTouchEvent方法。
否则:
通过DecorView向下层分发事件。
简单的说,子View处理事件的优先级高于Activity
2.View的onTouch()和View的onTouchEvent()
简化一下View的dispatchTouchEvent()函数源码:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }

        if (!result && onTouchEvent(event)) {
            result = true;
        }
    }

可以看出,mOnTouchListener.onTouch()的优先级高于onTouchEvent(),调用了onTouch(),就不再调用onTouchEvent(),且它们处理的是同一个event事件。

3.三者之间的关系:
1.优先级View的onTouch()>View的onTouchEvent()>Activity的onTouchEvent()
2.View的onTouch()和View的onTouchEvent()函数处理都是同一个event事件,onTouch()处理了,则onTouchEvent()不再处理。
3.onTouchEvent()也有返回值,假如最终的子View的onTouchEvent()返回为false,则改事件会反馈到它的父级viewGroup的onTouchEvent()进行处理,如果一直返回false,则一直反馈到Activity的onTouchEvent()。