事件传递机制
Posted wangweizu99
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事件传递机制相关的知识,希望对你有一定的参考价值。
事件传递机制
1.基础认知
1.1事件分发的对象:点击事件(Touch事件)(什么是事件?)
-
定义:当用户触摸屏幕时,产生的点击事件(Touch事件)
-
事件的类型:
MotionEvent.ACTION_DOWN 按下View(事件的开始) MotionEvent.ACTION_UP 抬起View(与DOWN对应) MotionEvent.ACTION_MOVE 滑动View //MotionEvent.AVTION_CANCEL 结束事件(非人为结束)
-
一组事件的产生(图):
1.2事件传递的本质(事件传递是什么?)
当一个点击事件(MotionEvent)产生之后,系统把这一个事件传递给一个具体的View去处理的过程
先执行onTouch(),在执行onClick()
1.3事件传递的顺序
事件一般在 Activity 、 ViewGroup 、 View之间传递。
顺序:Activity -> ViewGroup -> View
1.4事件传递过程中的方法
- dispatchTouchEvent() 传递点击事件 当点击事件能够传递给当前View时,该方法调用
- onTouchEvent() 处理点击事件 在dispatchTouchEvent()内部调用
- onInterceptTouchEvent() 判断是否拦截了某个事件 在ViewGroup的dispatchTouchEvent()内部调用
1.5总结
2.先看总体(事件是怎么传递的?)
整个事件传递的过程就相当于一个递归的过程:
针对一个事件(ACTION_DOWN)的传递过程:
- dispatchTouchEvent()和onTouchEvent():
- return true 终结事件的传递
- return false 事件回传到父控件的onTouchEvent()处理:区别dispatchTouchEvent()事件停止向子View传递,onTouchEvent()不消费事件(无法处理事件)
- return super.xxxx() 事件继续传递完成递归过程,ViewGroup的dispatchTouchEvent()调用时会默认执行 onInterceptTouchEvent()
- onInterceptTouchEvent():
- return true 拦截事件并交给自己的onTouchEvent()处理
- return false或super 不拦截事件,并将事件传递给子View
3.详细解每个过程
4.总结
当一个控件接受一组传递的开始事件(ACTION_DOWN)并进行处理后:
-
dispatchTouchEvent() return true 那么事件就会停止传递
-
onTouchEvent() return true 剩余的事件(ACTION_UP、ACTION_MOVE)会直接传递到该控件的onTouchEvent()处理结束传递
-
一组触摸事件分为按下、移动、抬起,称之为一个事件序列,其中移动事件会有多个。当一个View决定自己消费一组事件需要在按下时就给出结果,反之如果在按下时决定消费意味着这一组事件序列均由自己消费。
4.1两个实验
-
在View的dispatchTouchEvent()返回false 并在ViewGroup的onTouchEvent()返回true
红色代表DOWN 蓝色代表 MOVE和UP
-
在ViewGroup的onTouchEvent()返回true
红色代表DOWN 蓝色代表 MOVE和UP
4.2 onTouch()和onTouchEvent()的区别
两个方法都在dispatchTouchEvent()中调用,onTouch()优先级较高
若果onTouch()中返回true则onTouchEvent()不在执行
onTouch能够执行的前提:
- mOnTouchListener不为空
- 点前点击的控件必须是ENABLED??
5.常见问题及解决(事件传递过程中会遇到什么?)
5.1常见的滑动冲突
- 滑动方向不一致
- 滑动方向一致
- 多层滑动嵌套
5.2滑动冲突的解决方法
-
外部拦截法
外部拦截法,就是所有事件都先经过父容器的拦截处理,由父容器来决定是否拦截。这种方式需要重写父容器的onInterceptTouchEvent()方法
- 不拦截ACTION_DOWN事件
- ACTION_MOVE事件根据需求判断是否拦截
- ACTION_UP必须放回false
-
内部拦截法
内部拦截法是指父容器不拦截任何事件,所有事件都传递给子元素。内部拦截法需要配合requestDisallowInterceptTouchEvent()方法才能正常工作。这种方式需要重写子元素的dispatchTouchEvent()方法
6.借鉴
图来自:https://juejin.cn/post/6844903472395976711
内容总结自:https://juejin.cn/post/6844903472395976711
https://jsonchao.github.io/
http://blog.csdn.net/guolin_blog/article/details/9097463
7.疑问
- 每次解决冲突都要重写布局?
- 两个主fragment不存在嵌套,是否改为一个Activity嵌套一个Fragment在嵌套一个Fragment?
guolin_blog/article/details/9097463
7.疑问
- 每次解决冲突都要重写布局?
- 两个主fragment不存在嵌套,是否改为一个Activity嵌套一个Fragment在嵌套一个Fragment?
以上是关于事件传递机制的主要内容,如果未能解决你的问题,请参考以下文章
Android Touch事件传递机制全面解析(从WMS到View树)