从android源码角度分析touch机制
来源:互联网 发布:js中树形菜单制作方法 编辑:程序博客网 时间:2024/05/14 13:37
Touch概述
Touch操作即是用手触摸或者用鼠标操作屏幕所造成的事件触发。这些事件最基本的包括按下Down,移动Move,取消Cancel和离开触摸屏Up四种事件。一个完整的Touch过程一般是由Down->(Move)->Up/Cancel这四个事件组成,值得注意的是,一个完整的触摸事件必须由Down开始,再到Up/Cancel结束,中间的Move可以有可以没有,当然Touch事件不止这四个事件,但这四个事件是最基本,开发中必须考虑到的。
当用户开启应用触摸屏幕,系统服务就通过IPC(Binder)通知应用的主线程Looper中,最终传递到我们应用中Activity,View和ViewGroup中。
需要对Touch机制清晰才可以解决以下一些类似问题:
1. touch监听没被调用到
2. 双层滑动模块嵌套后发生滑动不了的现象
3. 设置了onClickListener后,点击View没有反馈
4. 点击两下View才调用onClickListener的bug
宏观
以上是Touch事件的传递顺序,一个Touch事件要传递到View中,必须经过Activity向下分发,如果在ViewGroup在子View中找到可以处理这个事件的View,则向下再传递下去,否则ViewGroup会尝试处理这个事件。下面详细介绍View,ViewGroup,Activity这三个类收到Touch事件的处理已经它们如何分发Touch事件。
View的Touch逻辑
Android中View对于Touch的处理逻辑主要集中在以下三个个位置中
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
以上几个方法返回值为true代表事件被处理,如果返回false,则代表事件没有被处理。
View之dispatchTouchEvent
让我们看一下dispatchTouchEvent
的逻辑,删除部分不重要代码,源码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
从上面的源码中可以看出View的dispatchTouchEvent()
主要的逻辑如下:
1.停止嵌套滑动(5.0以后添加的)
2.做了安全监测,如果View开启了安全检测(setFilterTouchesWhenObscured(true)
)并且当前View所在的Window被其他Window遮盖的话,则不会调用再处理Touch事件
3.如果当前View使能,才会调用OnTouchListener
4.不管使能与否,只要OnTouchListener没有处理事件,就会让onTouchEvent()
来处理事件
View之onTouchEvent
前面我们已经知道如果事件没有被OnTouchListener处理的话,将会被onTouchEvent()
处理。 onTouchEvent()
在源码中主要是处理
- 1
- 2
- 3
- 4
- 5
让我们看一下OnTouchListener
的逻辑,源码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
View的onTouch方法归纳为一下几点:
1.不管View使能与否,只要clickable或者longclickable,就一定消费事件(返回true)
2.如果View不使能,并且clickable或者longclick,就只会消费事件但不做其他任何操作
3.如果View使能,先看看TouchDelegate消费与否,如果不消费再给自己消费
4.处理包括focus,press,click,longclick
ViewGroup的Touch逻辑
而ViewGroup继承与View,并覆盖了
- 1
而且比View多了一个处理Touch的位置:
- 1
这个方法的返回值主要用于是否阻止向子View派发触摸事件,默认返回false,不阻止。
精简后的源码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
综上,ViewGroup的主要的任务是找一个Target,并且用这个target传递事件,主要逻辑如下
1.在Down并且不拦截的时候会多出一个寻找Target的过程,在这个过程中遍历子View,如果子View的dispatchTouch为true,则这个子View就是当前ViewGroup的Target。找Target是处理Down事件时候特有的,其他事件不会触发找Target。
2.如果没有Target,则发送把自己当做一个View去处理这个事件(super.dispatchTouch()
)
3.如果有Target并且拦截,则发送Cancel给子View
4.如果有Target并且不拦截,则调用Target的dispatchTouch
5.可以利用requestDisallowInterceptTouchEvent(boolean)来强制viewparent不拦截事件。但是作用域限于一个Touch的过程(Down->Up/Cancel)
Activity的Touch逻辑
ViewGroup收到的事件是由Activity发送出去的。Activity的Touch逻辑非常简单,源码如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
Activity的Touch逻辑归纳如下:
Activity将事件经过一些步骤发送给ContentView,如果ContentView没消费,就交给Activity自己处理。
问题解决
文章开头提出了几个问题,可以用这篇文章的分析解决:
touch监听器没被调用到?
看View.dispatchTouchEvent()
,ViewGroup.dispatchTouchEvent()
a)如果是View非使能,直接用setEnabled(true)
b)如果是事件被这个View的viewparent拦截了。可以修改这个viewparent的onInterceptTouchTouchEvent()
,或者在这个View中调用getParent().requestDisallowInterceptTouchEvent()
双层滑动模块嵌套后发生滑动不了的现象?
看ViewGroup.dispatchTouchEvent()
如果是事件被这个View的viewparent拦截了。可以修改这个viewparent的onInterceptTouchTouchEvent()
,或者在这个View中调用getParent().requestDisallowInterceptTouchEvent()
设置了onClickListener后,点击View没有反应?
看View.onTouchEvent()
a)如果是View非使能,直接用setEnabled(true)
b)可能覆盖了onTouchEvent(),需要在覆盖的方法调用super.onTouchEvent()
或者手动调用performClick()点击两下View才调用onClickListener的bug?
看View.onTouchEvent()
这个其实是安卓的设计,当某个View调用了setFocusableInTouchMode(true)
后,第一次点击会引起这个View的focus,第二次点击才会调用onClickListener,只需要设置setFocusableInTouchMode(false)
即可。
- 从android源码角度分析touch机制
- Android 从源码角度分析事件分发机制(三)
- 从源码角度分析Android中的Binder机制的前因后果
- 从源码角度分析android事件分发处理机制
- 从源码的角度分析Android消息处理机制
- 从源码角度分析android事件分发处理机制
- 从源码角度分析android中的消息机制
- 从Android源码的角度理解应用开发(1)-Touch机制
- 从Android源码的角度理解应用开发(1)-Touch机制
- Handler机制-从源码角度分析
- 从源码角度解析Android消息机制
- 【Android】从源码角度看Handler机制
- 从源码角度分析Android Context 对象
- 从源码角度分析Android View的绘制机制(一)
- 从源码角度分析Android系统的异常捕获机制是如何运行的
- Android 从源码角度分析消息处理机制(Handler,Looper,Message)
- 从源码角度分析linearLayout测量过程以及weight机制
- 从源码角度分析java层Handler机制
- 使用moveTaskToback()让APP退到后台
- javaee之java基础加强
- HDU 2181 哈密顿绕行世界问题(搜索)
- SpringMvc的重要组件介绍
- Java学习(七)
- 从android源码角度分析touch机制
- Html标题和段落
- HDU 1043 Eight(BFS)
- log4j配置信息
- Java7并发编程--3、线程同步辅助类
- PropertiesConfiguration读取属性文件
- wordpress 修改固定连接提示页面404错误
- 【BZOJ3956】Count,单调栈+ST表维护区间最大值
- Jsp页面迭代、取值、选择标签