硬件设备事件信号采集传输到上层:
Android Framework源码-IMS随记_暮冬一十四的博客-优快云博客
WMS中有个WindowState集合,WMS最终会将事件封装为MotionEvent对象通过调用->Activity.dispatchTouchEvent(MotionEvent ev)->PhoneWindow->ViewRootImpl->ViewGroup->View进行事件分发;
事件分发角色:
Activity、ViewGroup、View;
U型链:
事件通过Activity->ViewGroup->View分发过程中没有被消费;
ps:实际代码中是每次调用dispatchTouchEvent时,是递归调用的,返回的时候也要逐层往上返回,所以实际是按照绿色箭头路径依次返回,看着是一个U型;
L型链:
事件通过Activity->ViewGroup->View分发过程中被消费了;
事件分发中的主要函数:
dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent
ViewGroup事件分发:
继承自View;View这个父类有onTouchEvent()和点击事件mOnClickListener;
- dispatchTouchEvent(ev)
- 判断是否拦截onInterceptTouchEvent();
- 拦截时:dispatchTransformedTouchEvent(ev,childView=null):childView=null时,调用super.onTouchEvent(ev):实际就是执行自己的onTouchEvent;
- 在onTouchEvent(ev)判断是否有用户设置的mOnClickListener;
- 有mOnClickListener就执行;并且return true;表示事件被自己消费;
- 没有mOnClickListener则return false;表示事件没有被自己消费;
- 不再往下分发事件;
- 不拦截时:
- 判断是否为action_down事件
- 是action_down事件:
- 先去根据子View的Z轴进行排序,z越小放在list的最后面;保证最上层的view,先被之后遍历到;
- 开启for循环,倒着遍历子View(i--);
- 遍历自己的子View:判断点击的XY坐标在哪个子View中,遍历到就返回childView,没遍历到childView=null;
- 调用dispatchTransformedTouchEvent(ev,childView)
- 判断childView==null时,调用自己的super.onTouchEvent(ev); 走上面4、5、6逻辑;
- 判断childView不为null时,调用childView.dispatchTouchEvent()
- 不是action_down事件:
- 直接拿到mFirstTouchTarget这个view集合的单向链表
- while循环链表dispatchTransformedTouchEvent(ev,mFirstTouchTarget.child)分发事件;后面会讲mFirstTouchTarget;
View事件分发:
- 上面流程中ViewGroup调用childview.dispatchTouchEvent(ev):
- 判断用户是否设置了mOnTouchListener事件;
- 有mOnTouchListener则执行mOnTouchListener,直接return true;表示事件被消费,不再往下执行;
- 没有mOnTouchListener时:
- 调用onTouchEvent(ev),
- 在onTouchEvent(ev)判断是否有用户设置的mOnClickListener;
- 有mOnClickListener就执行;并且return true;表示事件被消费;
- 没有mOnClickListener则return false;表示事件没有被消费;
mFirstTouchTarget:
是一个单向链表;在action_move时使用;
- 在ViewGroup产生action_down事件时,并且被子view消费的时候,会将消费事件的view封装为TouchTarget对象,放到mFirstTouchTarget这个单向链表中;
- 产生action_move的时候,不再去走action_down的遍历,直接拿到mFirstTouchTarget这个view集合的单向链表
- while循环链表dispatchTransformedTouchEvent()分发事件
ps:经过上面的梳理,会发现当函数返回值为true时,表示事件被消费了;
判断事件是否是滑动事件:
不能只通过ev.getAction()==ACTION_MOVE来判断;
因为手指点击屏幕时,是一个面接触到屏幕。不管手动是否动了,底层传感器都会发生1次Down和N次Move事件;
所以要在ACTION_MOVE中通过判断滑动距离是否超过手机的最小滑动距离像素来判断:
/*** 获取手机最小滑动距离的像素;* 每个手机的值不一样;* 同一个手机在不同的APP中值是一样的;* 用来判断是否是滑动事件*/ int minTouchSlop = ViewConfiguration.get(contenx).getScanledTouchSlop();