事件分发机制

down事件传递:

假设事件已经传递到viewgroup中来了,也就是执行viewgroup中的dispatchTouchEvent()方法,如果是down事件就清空当前的状态,里面会有mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT,然后是为intercepted赋值,如果没有重写父容器的onInterceptTouchEvent()这个方法,那默认返回intercepted为false,如果没有取消也就是canceled为false,这两个参数均为false的情况下,并且事件是的down事件的情况下,事件可以向下传递,首先会调用buildTouchDispatchChildList()这个方法通过子view的当前在z轴位置来确定排序的view集合;之后是通过index最大的那个子view开始进行遍历这个view集合,如果这个view是可见的,并且点击事件在这个view的范围内,如果不符合上述条件就continue,符合就需要执行dispatchTransformedTouchEvent()这个方法,在这个方法里就会调用子view的dispatchTouchEvent(ev)并且将handle的值返回出去,如果子view消费了这个事件,那就是dispatchTransformedTouchEvent()这个方法返回为true,会将mFirstTouchTarget赋值成包装好的消费的子view的target以及newTouchTarget,同时将alreadyDispatchedToNewTouchTarget赋值为true,最后是通过mFirstTouchTarget的判空去返回handled的值也就是viewgroup中的dispatchTouchEvent方法的值,如果是alreadyDispatchedToNewTouchTarget为true并且target== newTouchTarget,直接返回true。

move事件传递:

1、mFirstTouchTarget!=null && intercepted== true,最终由于alreadyDispatchedToNewTouchTarget为false,通过intercepted为true将cancelChild为true,调用dispatchTransformedTouchEvent(ev,true,target.child, target.pointerIdBits)这条线,因为cancelChild是true,所以子view也不能消耗事件只是把事件设置为取消状态,由于事件是连续的所以mFirstTouchTarget会一直被赋值,赋值为下一个child,直到最后,成为空,也就是mFirstTouchTarget=null就会在dispatchTransformedTouchEvent()这个方法中调用child为空的那些判定super.dispatchTouchEvent(),也就是viewgroup自身去处理事件了。
2、mFirstTouchTarget!= null && intercepted == false;因为alreadyDispatchedToNewTouchTarget为false,以及cancelChild也为false,子view不为空所以调用child.dispatchTouchEvent(event)去返回handled,子view自己处理事件。
3、mFirstTouchTarget==null,就会在dispatchTransformedTouchEvent()这个方法中调用child为空的那些判定super.dispatchTouchEvent(),也就是viewgroup自身去处理事件了。

onClick、onTouchEvent、onTouch这三个的关系?

在view的dispatchTouchEvent(MotionEvent ev)方法,有两个if判断,用来判断是否执行view的onClick(),首先第一个if有四个条件,第一个就是触摸监听的ListenerInfo这个变量不为空,第二个这个变量的mOnTouchListener也不为空,第三个这个view可以被点击,第四个它的onTouch()方法返回的boolean值,这四个条件全是与判断,也就是其中一个不成立,就会通过事件消费onTouchEvent(event)方法,执行到onClick事件,如果全返回true,那就会屏蔽掉onTouchEvent方法的执行。在onTouchEvent方法中会调用performClickInternal()方法,而performClickInternal方法会调用performClick这个方法,在这个方法里会拿到onClickListener事件的监听最终去执行onClick方法。

单点触控

单点触控

多点触控

多点触控 ( Multitouch,也称 Multi-touch ),即同时接受屏幕上多个点的人机交互操作,多点触 控是从 Android 2.0 开始引入的功能


多点触控
多点触控流程
Android页面View的体系结构

事件大分发流程

1.事件返回时 dispatchTouchEvent 直接指 向了父View的 onTouchEvent 这一部分是不 合理的,实际上它仅仅是给了父View 的 dispatchTouchEvent 一个 false 返回值, 父View根据返回值来调用自身 的 onTouchEvent。 2.ViewGroup 是根 据 onInterceptTouchEvent 的返回值来确定 是调用子View的 dispatchTouchEvent 还是 自身的 onTouchEvent, 并没有将调用交给onInterceptTouchEvent。

public boolean dispatchTouchEvent(MotionEvent ev) { boolean result = false; // 默认状态为没有消费过 if (!onInterceptTouchEvent(ev)) { // 如果没有拦截交给子View result = child.dispatchTouchEvent(ev); }if (!result) { // 如果事件没有被消费,询问自身onTouchEvent result = onTouchEvent(ev); }return result; }
事件大分发流程

View消费了事件

View消费了事件

ViewGroup消费了事件

ViewGroup消费了事件
public boolean dispatchTouchEvent(MotionEvent ev) { // 默认状态为没有消费过 boolean result = false; //决定是否拦截 final boolean intercepted = false; if (!requestDisallowInterceptTouchEvent()) { intercepted = onInterceptTouchEvent(ev); }//找出最适合接收的孩子 if (!intercepted && (DOWN || POINTER_DOWN || HOVER_MOVE)) { // 如果没有拦截交给子View for (int i = childrenCount - 1; i >= 0; i--) { mFirstTouchTarget = child.dispatchTouchEvent(ev); } }//分发事件 if (mFirstTouchTarget == null) { // 如果事件没有被消费,询问自身onTouchEvent result = onTouchEvent(ev); } else { for(TouchTarget touchTarget : mFirstTouchTarget) { result = touchTarget.child.dispatchTouchEvent(ev); } }return result; }

1: 为什么 View 会有 dispatchTouchEvent ?

A: 我们知道 View 可以注册很多事件监听器,例如:单击事件(onClick)、长按事件(onLongClick)、触 摸事件(onTouch),并且View自身也有 onTouchEvent 方法,那么问题来了,这么多与事件相关的方 法应该由谁管理?毋庸置疑就是 dispatchTouchEvent,所以 View 也会有事件分发。

2: 与 View 事件相关的各个方法调用顺序是怎样的?

•单击事件(onClickListener) 需要两个两个事件(ACTION_DOWN 和 ACTION_UP )才能触发,如 果先分配给onClick判断,等它判断完,用户手指已经离开屏幕,黄花菜都凉了,定然造成 View 无法 响应其他事件,应该最后调用。(最后) •长按事件(onLongClickListener) 同理,也是需要长时间等待才能出结果,肯定不能排到前面,但因 为不需要ACTION_UP,应该排在 onClick 前面。(onLongClickListener > onClickListener) •触摸事件(onTouchListener) 如果用户注册了触摸事件,说明用户要自己处理触摸事件了,这个应该 排在最前面。(最前) •View自身处理(onTouchEvent) 提供了一种默认的处理方式,如果用户已经处理好了,也就不需要 了,所以应该排在 onTouchListener 后面。(onTouchListener > onTouchEvent)

TouchTarget和mFirstTouchTarget, 这个变量是给手势设置的,跨越事件保留的

1、mFirstTouchTarget是TouchTarget,是一个链表;
2、mFirstTouchTarget记录的是该view的第一个接收该手势的子view;
3、mFirstTouchTarget的next的TouchTarget记录的是这个手势的其他手指或者鼠标所在的子view;
4、mFirstTouchTarget是一个view group是否有孩子处理该事件的一个标志,为null表明没有孩子处理它, 否则表明action_down已经分发给他的孩子了;
5、mFirstTouchTarget是View group的成员变量,标志着每个view group都有一个这样的变量,如果一 个手势被一个view处理,那么他的父亲和祖父们的mFirstTouchTarget都不会为null;

局部变量: newTouchTarget & alreadyDispatchedToNewTouchTarget

辅助功能时间分发

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容