关于事件分发的一些认识
来源:互联网 发布:多线程并发 数据共享 编辑:程序博客网 时间:2024/06/17 13:43
首先得说个起着决定性作用的东西:ACTION_CANCEL事件
在一个博客中找到了关于cancel事件产生的原因:
http://tianshanxuester.github.io/android/2013/11/13/Android-%E8%A7%A6%E6%91%B8%E4%BA%8B%E4%BB%B6.html
要触发ACTION_CANCEL,就先得了解一个类ViewGroup,ViewGroup是一个放置其他views(子view)的特殊view,它是布局类(*Layout)、视图容器(ListView、GridView、HorizontalScrollView、TabHost等等很多)的基类。
也就是说ViewGroup一般是做为父视图来容纳、管理其他子视图的。既然管理,在用户手势操作过程中,就会存在父视图不希望子视图响应用户手势操作的情况。Android提供了一个函数public boolean onInterceptTouchEvent (MotionEvent ev),在用户手势操作时,系统先调用父视图(一个继承自ViewGroup的类)的这个函数,来决定当前手势操作是由父视图还是子视图来响应、处理。我们仔细看看这个函数名,函数名中有一个单词intercept,经过查词典,这个单词的中文意思是拦截。在用户的一个完整手势操作过程中(起自ACTION_DOWN,终于ACTION_UP),对于每一次的MotionEvent``Android都会调用该函数,向父视图查询是否拦截当前MotionEvent,如果父视图返回false:不拦截,则系统会调用子视图的onTouchEvent函数;如果父视图返回true:拦截,则系统调用父视图的onTouchEvent。等等,有人不禁要问了,如果在这个完整手势操作过程中,父视图初期返回false、后期返回true会是一个什么样的情况呢(捣乱的来了)?这个嘛,是这个样子的,一开始返回false,毫无疑问,子视图会被调用onTouchEvent,但凡父视图在函数onInterceptTouch中有一次返回了true,那这一完整手势操作内所有后续的MotionEvent都会调用父视图的onTouchEvent,即使父视图后期反悔而改成返回false也不行(没有后悔药)。在这种父视图先返回false,后返回true的情况下,子视图收不到后续的事件,而只是在父视图由返回false改成返回true(拦截)的时候收到ACTION_CANCEL事件
源码:点击打开链接
现在说说具体项目问题
我们知道,down事件发生的时候,如果子view的dispatchTouchEvent返回了true,那么在viewgroup的dispatchTouchEvent方法中mFirstTouchTarget会被赋值,代表有子view消耗了事件,根据viewgroup中事件分发的代码:
if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { intercepted = onInterceptTouchEvent(ev); ev.setAction(action); // restore action in case it was changed } else { intercepted = false; } } else { // There are no touch targets and this action is not an initial down // so this view group continues to intercept touches. intercepted = true; }我们假设down事件的时候子view的dispatchTouchEvent返回了true,并且在返回true之前执行了getParent().requestDisallowInterceptTouchEvent(false);按理来说disallowIntercept的值会被置为false,那么后续的move事件到来时,必定会走onIntercepteTouchEvent方法,这个本事是没有错的。可是在使用过程中,我的父容器是scrollview,子view是listview,在执行scrollview的onIntercepteTouchEvent时候,当满足一定条件scrollview的onIntercepteTouchEvent会返回true(scrollview在down的时候是返回false的,应该所有的父容器都是,要不然子view永远拿不到任何事件),down的时候返回了false,move的过程中返回了true,这会触发cancel事件,cancel事件触发之后
// Check for cancelation. final boolean canceled = resetCancelNextUpFlag(this) || actionMasked == MotionEvent.ACTION_CANCEL;
if (canceled || actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { resetTouchState(); } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) { final int actionIndex = ev.getActionIndex(); final int idBitsToRemove = 1 << ev.getPointerId(actionIndex); removePointersFromTouchTargets(idBitsToRemove); }
cancel事件触发之后 同样会执行resetTouchState方法,这个方法会将mFirstTouchTarget置为null,所以后续move事件传递到scrollview时不会执行onIntercepteTouchEvent方法,之前一直纠结为什么不执行。
- 关于事件分发的一些认识
- 关于事件的分发
- 关于Android事件分发机制一些要注意的问题
- 事件分发全面认识
- 关于对 Unity 3D Strange IoC 框架事件分发器的认识
- 关于View的事件分发
- 关于事件分发的笔记
- 关于事件分发的过程
- 关于winpcap的一些认识
- 关于AOP的一些认识
- 关于winpcap的一些认识
- 关于BIRT的一些认识
- 关于ARM的一些认识
- 关于random的一些认识
- 关于纹理的一些认识
- 关于tokyo的一些认识
- 关于索引的一些认识
- 关于Layer的一些认识
- 计算机网络复习(第五章 运输层)
- android学习(五) 向另一个应用发送用户 Intent
- 返回顶部 jQuery+css实现
- iOS 蓝牙开发 app作为外设被连接的实现(三)
- 百度音乐api接口
- 关于事件分发的一些认识
- BootStrap3.X模态框垂直居中显示
- MQTT V3.1--我的理解
- leetcode 371
- NBUT1597:Find MaxXorSum(字典树)
- Python引用(import)文件夹下的py文件的方法
- Android 静态代码分析
- 南宁H5EDU学员html/css阶段项目
- SSL 2628——2012年佛山市GDOI选拔赛题 循环小数【数学】