Android事件分发 | View分发事件

942 阅读3分钟

前文

前面说了点击事件由Activity传递给ViewGroup的过程,以及ViewGroup是如何分发事件的,关于ViewGroup的事件分发非常重要,涉及到我们经常遇到的问题:滑动冲突,所以要仔细理解。

该系列文章链接:

Android事件分发 | Activity分发事件 - 掘金 (juejin.cn)

Android事件分发 | ViewGroup分发事件 - 掘金 (juejin.cn)

现在就把最后的一部分给回顾一下。

正文

在我们平时开发中,对于自定义View,我们一般都是继承至已经实现的View或者ViewGroup,对于直接继承至View的情况还是比较少的,刚好最近做了一个项目,其中就有一个自定义View继承至View,所以这方面知识需要加深一下。

事件分发到View也是分发到底了,这部分也比较简单。

dispatchTouchEvent方法

直接来看一下View的dispatchTouchEvent关键代码:

//View的dispatchTouchEvent方法 关键代码
ListenerInfo li = mListenerInfo;
//先判断是否设置TouchListener
if (li != null && li.mOnTouchListener != null
        && (mViewFlags & ENABLED_MASK) == ENABLED
        && li.mOnTouchListener.onTouch(this, event)) {
    result = true;
}
//再判断onTouchEvent返回值
if (!result && onTouchEvent(event)) {
    result = true;
}

这里基本就是全部的代码了,其中dispatchTouchEvent的返回值就是代表是否消费掉点击事件,这个返回值直接影响着其上层View是否需要再调用自己的处理逻辑(对于ViewGroup来说是调用super.dispatchTouchEvent,对于Activity来说是调用onTouchEvent)。

3个判断条件

这里第一个if有3个判断条件,当全是ture则不会再执行onTouchEvent方法,这里要记住。

  1. "mOnTouchListener != null" ,即这个View设置了OnTouchListener

  2. "(mViewFlags & ENABLED_MASK) == ENABLED",这个View是可点击的,对于View来说,默认是可点击的。

  3. "mOnTouchListener.onTouch"的返回值为true。

这里3个条件还是蛮苛刻的,原因很简单,一般我们很少自己给View设置TouchListener监听,即使设置了,也必须在onTouch返回true才可以,至于为什么这样,暂时还有深究过。

当3个条件有一个不为空,则执行onTouchEvent方法

onTouchEvent方法

对于onTouchEvent方法我们在自定义View时使用的较多,这个是在dispatchTouchEvent方法内部调用,这里其实就是对MotionEvent事件进行处理。

注意2点即可:

  1. 在处理UP事件时,是否需要回调ClickListener回调;

  2. 对于各种复杂的手势以及操作可以通过手势识别类来辅助完成。

流程图

这时我们需要想一下在实际场景中,什么情况才会把触摸事件传递给View的这几个方法,这里有2个地方会触发:

  1. 就是这个View它不是一个ViewGroup,它已经是最顶层的一个View了,这时事件传递给这个View。

  2. 就是这个View还是ViewGroup,事件在分发给子View没有被消耗,或者点击的是ViewGroup的空白地方,这时会触发ViewGroup的兜底策略,这时会把直接传递到View的方法中。

这里从其他博客拷贝一张觉得很不错的图,来表示一下流程:

image.png

这个流程完美诠释了dispatchTouchEvent()的返回值由来,以及几个监听器的优先级,这个非常重要。

当都设置了监听器时,TouchListener > onTouchEvent > onClickListener,当前一级的监听器返回true,则说明事件被消耗,不会再往下传递。

总结

对于View分发事件,总结重点如下:

  1. 要清楚什么情况下会调用View的dispatchTouchEvent()方法,一个是正常派发,一个是兜底。

  2. 在dispatchTouchEvent()中的返回值受到3种监听器影响,优先级高到底分别为:TouchListener、onTouchEvent和onClickListener,在实际业务中,要时刻注意这3者的优先级顺序。