Android事件分发总结

Posted 不会写代码的丝丽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android事件分发总结相关的知识,希望对你有一定的参考价值。

总是忘记又要去看源码所以直接记下结果方便以后阅读:
假设当前是

假设View的ClickAble为false(如果为true默认消费事件)decorView我们接触不到但是我还是想写下来

事件传播(默认):
触摸事件按下
1 Activity->dispatchTouchEvent
2 decorView->dispatchTouchEvent 不做详细分析因为我们开发者控制不到
3 decorView->onInterceptTouchEvent
4 开发者的ViewGroup->dispatchTouchEvent
5 开发者的ViewGroup->onInterceptTouchEvent
6 View->dispatchTouchEvent
7 View->onTouchEvent
8 ViewGroup->onTouchEvent
9 decorView->onTouchEvent
10 activity->onTouchEvent
触摸事件移动(因为上面的没有消费所以直接在Activity中消费)
11 Activity->dispatchTouchEvent
12 decorView->dispatchTouchEvent

(不会触发onInterceptTouchEvent因为内部mFirstTouchTarget为空)

13 activity->onTouchEvent

触摸事件抬起(因为上面的没有消费所以直接在Activity中消费)
14 Activity->dispatchTouchEvent
15 decorView->dispatchTouchEvent

(不会触发onInterceptTouchEvent因为内部mFirstTouchTarget为空)

16 activity->onTouchEvent


备注:
1 如果任意ViewGroup中如果onInterceptTouchEvent返回了一次true那么在本触摸事件的后序事件不会在调用onInterceptTouchEvent进行判断。假设触摸事件为
①按下 ②移动 ③移动 ④松开
假设在①按下事件调onInterceptTouchEvent 返回了false ②移动事件调用 onInterceptTouchEvent 返回了true 那么 ③移动 和 ④松开不会调用到onInterceptTouchEvent。 注意啊不影响dispatchTouchEvent收到完整通知,除非在触摸按下事件的时候dispatchTouchEvent返回了false
1.1 如果任意ViewGroup中如果onInterceptTouchEvent返回了true那么直接会调用super.onInterceptTouchEvent从而直接调用本ViewGroupontouchEvent.


2 ViewdispatchTouchEvent的实现默认调用onTouchEvent并作为返回值


3.1 ViewGroupdispatchTouchEvent会调用onInterceptTouchEvent 如果返回true那么会调用自身父类的ViewdispatchTouchEvent 也就是直接调用自身的onTouchEvent 。如果onInterceptTouchEvent返回false 交给子布局类的dispatchTouchEvent决定其自身的dispatchTouchEvent返回值。如果子布局类的dispatchTouchEvent返回false,那么调用ViewGroup的父类(也就是ViewGroup的父类View,简单点就是super.dispatchTouchEvent)的dispatchTouchEvent决定返回值。

3.2 如果ViewGroup在触摸按下的时候dispatchTouchEvent返回false那么dispatchTouchEvent收不到后序事件。
①按下 ②移动 ③移动 ④松开
假设上面的四个事件①返回了false ,②③④将收不到通知。

3.3 如果ViewGroup在触摸按下dispatchTouchEvent的时候返回true,会收到后序事件,哪怕你在移动事件返回了false依然会继续收到后序事件,只要你在按下事件返回了true
①按下 ②移动 ③移动 ④松开
假设上面的四个事件①返回了true ,②返回了false,③和 ④你依然会接受到事件通知。

3.4 onTouchEvent方法内部会判断手指松开事件然后回调onClick。并且该方法默认返回值的在该View为Clickable时返回true。也就是不调用默认实现无法监听点击事件

3.4 不管是ViewGroup还是View设置了OnTouch监听那么调用onTouchEvent前会调用OnTouch方法,如果OnTouch方法返回了true那么不会在调用onTouchEvent ,返回false那么才会调用onTouchEvent


4 中途拦截返回true情况。假设有如下情况

①按下 ②移动 ④松开
ViewDispatchTouchEvent直接返回了super.dispatchTouchEvent(ev) || true
ViewGrouponInterceptTouchEvent方法如果是移动事件那么返回true,其它触摸事件false

那么事件序列为
触摸事件按下

1 Activity->dispatchTouchEvent
2 decorView->dispatchTouchEvent
3 decorView->onInterceptTouchEvent
4 开发者的ViewGroup->dispatchTouchEvent
5 开发者的ViewGroup->onInterceptTouchEvent 返回false
6 View->dispatchTouchEvent 返回true
7 View->onTouchEvent

触摸事件移动
8 Activity->dispatchTouchEvent
9 decorView->dispatchTouchEvent
10 decorView->onInterceptTouchEvent
11 viewGroup->onInterceptTouchEvent 此时返回了true ,因为返回了true下次后续事件不会调用,注意dispatchTouchEvent不影响后序事件接收
12 View->dispatchTouchEvent 会受到一个cancel的触摸事件注意不是移动事件
13 View->onTouchEvent 会受到一个cancel的触摸事件注意不是移动事件。如果有监听点击事件此处也不会当抬起事件处理,也就是你设置了监听点击事件的将不会受到回调

触摸事件抬起(因为上面的没有消费所以直接在Activity中消费)
14 Activity->dispatchTouchEvent
15 decorView->dispatchTouchEvent
16 decorView->onInterceptTouchEvent
17 viewGroup->dispatchTouchEvent 不会调用拦截方法了哦。拦截方法返回了true后序事件不会在拦截判断了
18 viewGroup->onTouchEvent 看清楚了哦


5 ViewGroup 的 在受到按下事件的时候dispatchTouchEvent 返回false 后序事件将接收不到。假设按下返回true 移动的事件返回false 依然能接收到后序事件


6 ViewGroup 的 在受到按下事件的时候dispatchTouchEvent 返回true 且不调用super.dispatchTouchEvent 那么onInterceptTouchEventonTouchEvent不会调用。


7 ViewGroup 的 在受到按下事件的时候dispatchTouchEvent 返回true||super.dispatchTouchEvent 并且onInterceptTouchEvent返回了true,那么直接调用onTouchEvent且后序事件不会在调用经过onInterceptTouchEvent而是直接dispatchTouchEventonTouchEvent

8 ActivityonTouchEvent只有在子View的按下事件dispatchTouchEvent返回false时才会调用,也就是后序事件(注意是按下之后的关联后序事件)子ViewdispatchTouchEvent哪怕返回false (按下事件就是一个新的触摸事件),activity的 onTouchEvent也不会回调

用法解析

当一个ViewGroup不想子View调用触摸事件时onInterceptTouchEvent 返回true。如果自己想消费那么onInterceptTouchEvent返回truedispatchTouchEvent返回true,根据自身情况判断是否要super.dispatchTouchEvent

View是否会默认消费事件

如果View 的clickable或者longClickAble为true 那么不管是否enable都会消费事件

源码原理解析总结:

ViewGroup继承View,ViewGroup重写了ViewdispatchTouchEvent方法。内部调用逻辑大致如下

1 是否是按下事件?如果是调用onInterceptTouchEvent方法,如果onInterceptTouchEvent返回true那么调用View的dispatchTouchEvent方法且返回值作为自身返回值,而View默认dispatchTouchEvent实现为直接调用onTouchEvent作为返回值。onTouchEvent内部实现了点击监听的回调。

2 是否是按下事件?如果是调用onInterceptTouchEvent方法,如果onInterceptTouchEvent返回false 遍历子ViewdispatchTouchEvent方法,如果子ViewdispatchTouchEvent返回true,ViewGroup中一个属性mFirstTouchTarget保存这个View

3 不是按下事件且mFirstTouchTarget 为空那么 直接调用ViewGroupsuper.dispatchTouchEvent 从而调用自身onTouchEvent

3 不是按下事件且mFirstTouchTarget 不为空那么, 直接调用ViewGrouponInterceptTouchEvent ,如果返回为true,那么调用mFirstTouchTargetdispatchTouchEvent方法并且触摸事件变为取消事件cancelmFirstTouchTarget重变为null;另一种情况ViewGrouponInterceptTouchEvent 返回false,那么调用mFirstTouchTargetdispatchTouchEvent方法,注意这里不会重置mFirstTouchTarget属性

以上是关于Android事件分发总结的主要内容,如果未能解决你的问题,请参考以下文章

Android事件分发

Android触摸事件分发

浅谈Android 事件分发机制

Android事件分发机制总结

Android触摸事件分发机制完全解析《一》

Android事件分发总结