学习笔记:android事件分发梳理二(U型事件流,ViewGroup分发到View)

381 阅读3分钟

ViewGroup的事件分发主要有三个方法:

    //负责分发事件
    dispatchTouchEvent(MotionEvent ev)
    //负责拦截事件
    onInterceptTouchEvent(MotionEvent ev)
    //负责消费事件
    onTouchEvent(MotionEvent ev)

主要分析dispatchTouchEvent和onTouchEvent方法

U型事件流程图

假设当前activity中有一个ViewGroup,叫第一层容器,第一层容器这个ViewGroup中还有一个ViewGroup,叫第二层容器,第二层容器中有一个View,叫子view

事件从红色的第一层容器的dispatchTouchEvent方法开始分发 此时U型事件流在顶层

在第一层容器的dispatchTouchEvent中,倒序循环遍历了所有子控件,然后把每一个子控件传个了一个叫dispatchTransformedTouchEvent的方法,那么再来看dispatchTransformedTouchEvent方法

在dispatchTransformedTouchEvent中调用了这个子控件的dispatchTouchEvent方法,此时这个子控件就是蓝色的第二层容器,事件就从第一层容器传递到了第二层容器, 由于第二层容器也是一个ViewGroup,所以会继续执行ViewGroup中的dispatchTouchEvent方法,在第二层容器的dispatchTouchEvent方法中遍历所有的子控件

接下来就到了第二层容器的dispatchTransformedTouchEvent方法中

因为第三层子View是一个View,所以会执行View的dispatchTouchEvent方法,接下来看View的dispatchTouchEvent方法

这里可以看到onTouch是在onTouchEvent之前执行的,而onClickListener.onClick是在onTouchEvent中的,所以onTouch的优先级会高于onCLick,接下来再看view的onTouchEvent执行了什么

到此时这个事件流就结束了,也就是说事件在子view这一层被消费掉了,当然这是指我们有设置监听的情况下onTouchEvent返回true,这个事件才被消费掉,当我们没设置监听的时候

此时在U型流程图中,位于最低处,从最顶层(第一层容器)已近分发到了最下面一层的View(子view)。

如果我们这里没有设置监听,子view的onTouchEvent会返回false,来看看返回到了那里

返回到了第二层容器的dispatchTransformedTouchEvent方法,这个方法是在第二层容器的dispatchTouchEvent中调用,并且是在对子控件的遍历中调用的

mFristTouchTarget这个值会在每次ACTION_DOWN事件的时候被清空

那再来看看dispatchTransformedTouchEvent方法中参数child为null时会如何执行

第二层容器是个ViewGroup继承自View,所以此时调用super.dispatchTouchEvent会进入View的dispatchTouchEvent方法,就跟之前第三层子view的dispatchTouchEvent流程一样了,如果说在第二层容器里面也没有消费事件,也就是说第二层容器的super.dispatchTouchEvent返回的是false

那么第二层容器的dispatchTouchEvent方法返回的也是false,而第二层容器的dispatchTouchEvent是第一层容器调用的,所以这个false会返回到第一层容器中

同样第一层容器也不会进入 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) 这个代码块,所以第一层容器中的mFristTouchTarget也为null

在第一层容器的dispatchTransformedTouchEvent中,如果child为null则会调用super.dispatchTouchEvent方法,因为第一层容器也继承自View,所以会进入View的dispatchTouchEvent,在这里决定是否消费这个事件。

此时U型事件流又回到了顶层。

ps:在顶层view还没有消费该事件的情况下该事件会返回到activity的onTouchEvent中