View 的事件分发流程
最关键的 boolean —
- true 表示消费事件
- false 表示没有能力消费事件
Activity、Window、View 三者的关系
View 的结构图如下:
从上图中,我们可以知道它们三者的关系是:Activity > Window > View。
PhoneWindow 是 Window 的实现类,DecorView 是 PhoneWindow 的内部类,
事件传递的过程
事件收集之后最先传递给 Activity, 然后依次向下传递,大致如下:
|
|
这样的事件分发机制逻辑非常清晰,如果没有任何View消费掉事件,那么这个事件会按照反方向回传,最终传回给Activity,如果最后 Activity 也没有处理,本次事件才会被抛弃:
|
|
三个关键函数
- 分别为:
- dispatchTouchEvent(event)
- onInterceptTouchEvent(event)
- onTouchEvent(event)
它们三者的关系,ViewGroup 的事件分发机制伪代码如下:
|
|
相应的View 的 dispatchTouchEvent(event)
代码如下:
|
|
- 事件分发与消费
√
表示有该方法。
X
表示没有该方法。
类型 | 相关方法 | Activity | ViewGroup | View |
---|---|---|---|---|
事件分发 | dispatchTouchEvent | √ | √ | √ |
事件拦截 | onInterceptTouchEvent | X | √ | X |
事件消费 | onTouchEvent | √ | √ | √ |
事件处理的三种情况
子View 不处理事件
1view.onTouchEvent(event) --- false在这种情况下,子 View 并不处理事件,将事件的处理逐级的向上传递直到 Activity。如果 Activity 不处理,那么事件废弃。
子 View 处理事件
1view.onTouchEvent(event) --- true;此时,子 View 将消费 Touch 事件,
父 View 处理事件
1view.onTouchEvnet(event) --- true此时,父 View 将调用
onTouchEvent
方法消费 Touch 事件。
View 的事件处理
关键的代码如下:
|
|
这里面设计几个概念: onTouchListener 、Enable_mask、onTouchListener.onTouch()方法。
onTouchListener
它的来源如下:
123public void setOnTouchListener(OnTouchListener l) {mOnTouchListener = l;}只要我们调用了 View.setOnTouchListener() 那么第一个条件就成立。
onTouchListener.onTouch()
这是控件注册 onTouchListener 回调里的方法,如果返回 true,那么 dispatchTouchEvent 方法直接返回 true,否则执行 onTouchEvent(event) 方法。
由此可见在
onTouchListener
和onTouchEvent
两者谁先执行上,我们已经又了结论:如果设置了onTouchListener
,那么先执行onTouch(event)
方法;否则执行onTouchEvent
方法。
onTouchEvent
源码如下:
|
|
给出两个结论:
onClick 方法在 onTouchEvent 里。
1234567891011121314public boolean performClick() {final boolean result;final ListenerInfo li = mListenerInfo;if (li != null && li.mOnClickListener != null) {playSoundEffect(SoundEffectConstants.CLICK);li.mOnClickListener.onClick(this);result = true;} else {result = false;}sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);return result;}touch事件的层级传递
如果你在执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了。
简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action。
送上总结:
- Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。
- 在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。
- 子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。