Android 事件分发机制

硬件设备事件信号采集传输到上层:

Android Framework源码-IMS随记_暮冬一十四的博客-CSDN博客

WMS中有个WindowState集合,WMS最终会将事件封装为MotionEvent对象通过调用->Activity.dispatchTouchEvent(MotionEvent ev)->PhoneWindow->ViewRootImpl->ViewGroup->View进行事件分发;

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pqu5Yas5LiA5Y2B5Zub,size_20,color_FFFFFF,t_70,g_se,x_16

事件分发角色:

Activity、ViewGroup、View;

U型链:

事件通过Activity->ViewGroup->View分发过程中没有被消费;

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pqu5Yas5LiA5Y2B5Zub,size_20,color_FFFFFF,t_70,g_se,x_16

ps:实际代码中是每次调用dispatchTouchEvent时,是递归调用的,返回的时候也要逐层往上返回,所以实际是按照绿色箭头路径依次返回,看着是一个U型;

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pqu5Yas5LiA5Y2B5Zub,size_20,color_FFFFFF,t_70,g_se,x_16

L型链:

事件通过Activity->ViewGroup->View分发过程中被消费了;

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pqu5Yas5LiA5Y2B5Zub,size_20,color_FFFFFF,t_70,g_se,x_16

事件分发中的主要函数:

dispatchTouchEvent

onInterceptTouchEvent

onTouchEvent

 ViewGroup事件分发:

继承自View;View这个父类有onTouchEvent()和点击事件mOnClickListener;

  1. dispatchTouchEvent(ev)
  2. 判断是否拦截onInterceptTouchEvent();
  3. 拦截时:dispatchTransformedTouchEvent(ev,childView=null):childView=null时,调用super.onTouchEvent(ev):实际就是执行自己的onTouchEvent;
  4. 在onTouchEvent(ev)判断是否有用户设置的mOnClickListener;
  5. 有mOnClickListener就执行;并且return true;表示事件被自己消费;
  6. 没有mOnClickListener则return false;表示事件没有被自己消费;
  7. 不再往下分发事件;
  8. 不拦截时
  9. 判断是否为action_down事件
  10. 是action_down事件:
  11. 先去根据子View的Z轴进行排序,z越小放在list的最后面;保证最上层的view,先被之后遍历到;
  12. 开启for循环,倒着遍历子View(i--);
  13. 遍历自己的子View:判断点击的XY坐标在哪个子View中,遍历到就返回childView,没遍历到childView=null;
  14. 调用dispatchTransformedTouchEvent(ev,childView)
  15. 判断childView==null时,调用自己的super.onTouchEvent(ev); 走上面4、5、6逻辑;
  16. 判断childView不为null时,调用childView.dispatchTouchEvent()
  17. 不是action_down事件:
  18. 直接拿到mFirstTouchTarget这个view集合的单向链表
  19. while循环链表dispatchTransformedTouchEvent(ev,mFirstTouchTarget.child)分发事件;后面会讲mFirstTouchTarget;

View事件分发:

  1. 上面流程中ViewGroup调用childview.dispatchTouchEvent(ev):
  2. 判断用户是否设置了mOnTouchListener事件;
  3. 有mOnTouchListener则执行mOnTouchListener,直接return true;表示事件被消费,不再往下执行;
  4. 没有mOnTouchListener时:
  5. 调用onTouchEvent(ev),
  6. 在onTouchEvent(ev)判断是否有用户设置的mOnClickListener;
  7. 有mOnClickListener就执行;并且return true;表示事件被消费;
  8. 没有mOnClickListener则return false;表示事件没有被消费;

mFirstTouchTarget:

是一个单向链表;在action_move时使用;

  1. 在ViewGroup产生action_down事件时,并且被子view消费的时候,会将消费事件的view封装为TouchTarget对象,放到mFirstTouchTarget这个单向链表中;
  2. 产生action_move的时候,不再去走action_down的遍历,直接拿到mFirstTouchTarget这个view集合的单向链表
  3. while循环链表dispatchTransformedTouchEvent()分发事件

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pqu5Yas5LiA5Y2B5Zub,size_20,color_FFFFFF,t_70,g_se,x_16

ps:经过上面的梳理,会发现当函数返回值为true时,表示事件被消费了;

判断事件是否是滑动事件:

不能只通过ev.getAction()==ACTION_MOVE来判断;

因为手指点击屏幕时,是一个面接触到屏幕。不管手动是否动了,底层传感器都会发生1次Down和N次Move事件; 

所以要在ACTION_MOVE中通过判断滑动距离是否超过手机的最小滑动距离像素来判断:

/*** 获取手机最小滑动距离的像素;* 每个手机的值不一样;* 同一个手机在不同的APP中值是一样的;* 用来判断是否是滑动事件*/ int minTouchSlop = ViewConfiguration.get(contenx).getScanledTouchSlop();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值