安卓触摸事件传递机制
2016-09-14 11:28
302 查看
概述
安卓的触摸事件传递大体上是视图收到事件后进行决定是否要拦截,不拦截可以继续向内传递,拦截了不消费也可以回传给上层视图。事件类型主要有
ACTION_DOWN(按下)
ACTION_MOVE(移动)
ACTION_UP(抬起)
ACTION_CANCEL(取消)
前面三个很好理解,共同组成一次touch事件,有时候可能没有ACTION_MOVE。ACTION_CANCEL由系统自动产生,后面会介绍到。
touch事件传递机制涉及到View中的三个方法:
1)事件分发:
dispatchTouchEvent(MotionEvent ev);
2)事件拦截:ViewGroup才有
onInterceptTouchEvent(MotionEvent ev);
3)事件响应
onTouchEvent(MotionEvent ev);
注:OnTouchListener会优先于onTouchEvent()调用,此处先不予考虑。
调用顺序是
dispatchTouchEvent() ->onInterceptTouchEvent() -> onTouchEvent()。
根据具体的返回值(都为布尔型)可能传递过程有差异。
下面具体介绍下这几个方法:
1、事件分发 dispatchTouchEvent()
事件传递到一个view时最先执行dispatchTouchEvent()方法,如果dispatchTouchEvent()返回true,则事件不进行分发;
如果dispatchTouchEvent()返回false,则事件由上级ViewGroup的OnTouchEvent()处理;
如果dispatchTouchEvent()返回super.dispatchTouchEvent(),则由当前View处理,又分为:
当前是ViewGroup,传递到OnInterceptTouchEvent()决定是否要拦截
当前是普通View,直接传递到onTouchEvent()(因为ViewGroup才有OnInterceptTouchEvent()方法)。
2、事件拦截onInterceptTouchEvent()
这个方法时ViewGroup才有的,如果事件传递到当前ViewGroup,并且dispatchTouchEvent执行后确定要分发给当前view处理(返回super.dispatchTouchEvent()),则事件会传递到onInterceptTouchEvent()。根据返回值不同,可分为两种情况:
返回true,则确定要拦截事件并交给当前view的onTouchEvent()处理;
返回false,则不进行拦截,事件传递给子视图,子视图再进行分发、拦截、响应。
super.onInterceptTouchEvent()也是返回false。
有一个特例:
当ACTION_DOWN被当前view消费后,后续(同一次按下抬起过程中)的ACTION_MOVE和ACTION_UP会直接交给当前view的onTouchEvent(),不进入onInterceptTouchEvent(),不过还是要经过分发dispatchTouchEvent()。
这里的被当前view消费包括onInterceptTouchEvent()返回true直接消费和返回false传递给子view,但是子view不处理又传递给当前的view的onTouchEvent()处理。
3、触摸事件响应onTouchEvent()
跋山(分发)涉水(拦截),事件终于传递到当前view的onTouchEvent()来进行响应了,也是really 不容易。根据不同返回值:返回true,代表事件已消费,不再进行传递;
返回false,代表不消费此次事件,将事件传递给上一层的onTouchEvent()来处理,如果上层不消费,继续往上传递。
到这里触摸事件传递的基本流程已经讲完了,下面介绍几个特殊情况。
=======================我是分割线=========================
4、触摸事件监听器OnTouchListener
如果设置了onTouchListener,则所有传递给onTouchEvent()的事件会优先传递给onTouchListener的onTouch()方法。onTouch() return true: 事件已消费
onTouch() return false: 事件传递给onTouchEvent()
5、重叠视图的事件传递
假设有如下布局:<FrameLayout android:id="@+id/parentA" android:layout_width="match_parent" android:layout_height="match_parent"> <TestView android:id="@+id/childB" android:layout_width="match_parent" android:layout_height="match_parent"/> <TextView android:id="@+id/childA" android:layout_width="match_parent" android:layout_height="50dp" /> </FrameLayout>
FrameLayout parentA中有两个子视图, childA和childB,A覆盖于B之上(z轴重叠)。
注:接下来的分析都假设parentA不进行事件拦截。
当触摸childA所在区域,ACTION_DOWN事件先从parentA向childA传递。
如果事件成功被childA消费(onTouchEvent() 返回true),则以后的ACTION_MOVE和ACTION_UP也是传递给childA。
反之childA没有消费该ACTION_DOWN事件的话,则该事件继续传递给childA下面的childB,如果childB消费了ACTION_DOWN,则以后的ACTION_MOVE和ACTION_UP也是传递给childB。
总结:当视图发生重叠时,后续ACTION_MOVE和ACTION_UP的接收对象与ACTION_DOWN的接收对象保持一致。
6、ACTION_CANCEL何时产生
ACTION_CANCEL与前面介绍的几种事件不一样, 不由触摸直接产生,通常不会遇到。假设父视图parentA中有子视图childA,按下后假设ACTION_DOWN被childA消费了, 之后parentA拦截了ACTION_MOVE和ACTION_UP,则childA会收到ACTION_CANCEL事件(从事件分发dispatchTouchEvent()开始),产生该ACTION_CANCEL事件的ACTION_MOVE或者ACTION_UP事件也会停止,不传递到parentA的onTouchEvent(),即使他已经拦截了。
但是后续如果还有move或者up事件,parentA拦截下来还是会传递到onTouchEvent(),通常move事件是连续多次的不会有影响,但是如果一次触摸只有ACTION_DOWN和ACTION_UP,那么刚才这种情况就会导致ACTION_UP出发ACTION_CANCEL,而不被正确处理,需要注意。
总结:
一个视图处理了ACTION_DOWN事件,而没有收到后续的ACTION_MOVE和ACTION_UP(可能被拦截了),那么该视图就会收到ACTION_CANCEL,并且触发ACTION_CANCEL的MOVE或者UP也会立即停止,不继续传递不被消费。
写在最后
安卓touch事件传递流程还是很清晰的,最好学习的方式就是自己定义几个view重写dispatchTouchEvent(MotionEvent ev);
onInterceptTouchEvent(MotionEvent ev);
onTouchEvent(MotionEvent ev);
这个几个方法,分别对里面的ACTION_DOWN,ACTION_MOVE,ACTION_UP进行不同处理,返回不同值,打出log来分析。
在自定义功能复杂一点的View时,对touch事件的理解还是比较重要的,
还在学习,希望对大家有所帮助。
END.
相关文章推荐
- 9.4 触摸和手势:事件的传递的机制
- 触摸事件的传递机制
- android中的Touch触摸事件传递机制
- 彻底掌握Android的Touch触摸事件传递机制
- 触摸事件的传递机制和与Touch相结合的实践学习
- 9.5 触摸和手势:事件的传递的机制--演示代码
- Android 触摸事件分发传递机制
- [置顶] 安卓中滑动事件的传递机制及dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent的调用
- Android 触摸事件传递机制
- android触摸传递机制 - 拦截、事件分发
- 安卓中touch事件传递机制
- Android触摸事件传递机制学习笔记
- Android 触摸事件传递机制
- onTouchEvent用法解释以及触摸事件的传递机制
- android触摸事件传递机制以及onInterceptTouchEvent()和onTouchEvent()总结
- Android_触摸事件传递机制
- Android View 触摸事件传递机制
- Android ViewGroup 触摸事件传递机制
- 安卓事件传递机制
- 安卓事件传递机制个人理解版