Android学习笔记 - UI

事件分发机制

2019-04-26  本文已影响0人  CoderYuZ

事件顺序:

事件序列.png

Android中触摸事件主要相关的方法有三个:

一、事件从哪里开始,如果分发到View、ViewGroup?

当手指触摸屏幕的时候,事件是先从Activity的dispatchTouchEvent开始分发的,欲知分发过程,直接打开Activity源码,看dispatchTouchEvent方法:

    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            //这个方法是个空的,供子类实现,不管他
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

Activity的dispatchTouchEvent调用了getWindow().superDispatchTouchEvent(ev),也就是PhoneWindow的superDispatchTouchEvent()。继续深入,打开PhoneWindow源码:

    @Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
        return mDecor.superDispatchTouchEvent(event);
    }

PhoneWindow的superDispatchTouchEvent调用了mDecor的superDispatchTouchEvent,mDecor是DecorView的实例,DecorView集成自FrameLayout,所以事件就从Activity分发到了ViewGroup。顺序:Activity -> PhoneWindow -> DecorView -> ViewGroup

Activity的dispatchTouchEvent方法总结:如果mDecor(ViewGroup)的superDispatchTouchEvent返回true,Activity的dispatchTouchEvent就返回true;不然就调用Activity的onTouchEvent()。也就是说如果Activity中的View没有消费掉事件,事件最后会来到Activity的onTouchEvent中。

对PhoneWindow、DecorView的解释:View是如何被加载到屏幕窗口的


二、ViewGroup的dispatchTouchEvent(MotionEvent event)

代码有点多,说不清......来段伪代码:

    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean concume = false;
        //调用onInterceptTouchEvent判断是否拦截
        if (onInterceptTouchEvent(ev)){
            //拦截则调用自身的onTouchEvent
            concume = onTouchEvent(ev);
        }else{
            //不拦截,将事件分发给子View
            concume = child.dispatchTouchEvent(ev);
        }
        return  concume
    }

总之就是上面的注释,再抄一遍:调用onInterceptTouchEvent判断是否拦截,拦截则调用自身的onTouchEvent,不拦截,将事件分发给子View。
ViewGroup的dispatchTouchEvent源码中有几个点,这里列出来,方便之后阅读源码的理解,完整流程里有很多判断条件,可以去源码里详细了解:

三、View的dispatchTouchEvent(MotionEvent event)
    public boolean dispatchTouchEvent(MotionEvent ev) {
          ...
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

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

在View的dispatchTouchEvent中可以看出,如果View设置了OnTouchListener,并且OnTouchListener中的onTouch方法返回true,那么就不会执行View的onTouchEvent方法了。所以OnTouchListener.onTouch的优先级大于View的onTouchEvent。如果onTouch消费掉了,则onTouchEvent不会执行。

三、View的onTouchEvent(MotionEvent event)
    public boolean onTouchEvent(MotionEvent event) {
        ...
        // A disabled view that is clickable still consumes the touch
        // events, it just doesn't respond to them.
        //首先上面有一段注释意思是不管View是否可用,他都可以消费事件,只是不给出响应。
        ...
    }

源码去AS看,这里列出逻辑,方便之后阅读源码


总结

事件分发流程图(责任链模式):


事件分发模型.png

事件分发结论:

上一篇 下一篇

猜你喜欢

热点阅读