iOS事件分发机制介绍与应用

iOS事件分发机制介绍与应用

打开某App点击登录按钮后弹出登录页面。这是一个事件分发与响应的示例。我们来探究下该过程。

介绍事件分发机制自然绕不开事件。

iOS包含以下几种类型事件:

  • 触摸事件
  • 按压时间
  • 摇动事件
  • 远程控制事件
  • 编辑菜单时间

本文选择以触摸事件进行介绍。因为相对而言它包含的事件分发机制最全面。

iOS事件分发流程

iOS应用启动后UIApplicationMain函数会创建一个UIApplication的单例。该单例会维护一个FIFO的队列进行事件分发。系统检测到触摸事件后就会发给当前Application单例,由该单例进行派发。派发分为下面三个过程:

一、hitTest

UIWindow一旦接收到事件后就进行hit-test以查找哪个对象接收该事件。hitTest:withEvent方法用于发现在触摸位置的视图。pointInside:withEvent:用于检测该点击是否在视图的边界内。hitTest:withEvent调用pointInside:withEvent:

hitTest以递归的形式调用直至找到能处理触摸事件的最顶部叶子视图(一般就是手指点中区域所属的视图),那么该视图就会被选中。称为第一响应者。

做个类比就是:老板说我这有个事谁干给干了?经过经理等层层指派,大家都觉得小王合适。

该过程可以通过复写下面方法断点了解。

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

具体情况如图所示:

hit_test.png

二、sendEvent

一旦确定第一响应者后,UIApplication单例就会发送相关触摸事件到第一响应者。

就好比老本拍板说那就让小王干了。

该过程可以断点button的处理方法进行了解。如图所示:


sent_enent

三、事件处理

针对触摸事件的处理是重载如下方法:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;

第一响应者接到事件后有以下三种选择:

  1. 什么都不不处理(选择不重载上述方法)
  2. 处理一部分,剩下的交由其它对象处理(重载处理后调用super)
  3. 独自进行处理(重载处理并且不调用super)

如果第一响应者什么都不处理或者处理部分然后调用super,则事件将被发送到一个链式响应路径中,即响应链。该事件遵循以下路径进行转发:

  1. 第一响应者
  2. 第一响应者的父视图
  3. 父视图的父视图,直至关联的视图控制器
  4. 视图控制器的父视图控制器,直至根视图
  5. 根视图下一响应者是window
  6. window的下一响应者是application
  7. 最后的响应者是App delegate

若转发至App delegate,且App delegate未进行处理则该事件将被丢弃。

iOS处理方式

那么事件处理的方式有哪些?我们大致可以划分为下面三类。

  1. UIControl的子类
  2. TouchEvent
  3. 触摸相关手势。

有可能一个对象同时实现了两个或者更多处理方式。那么谁的优先级高些呢?

这个我们可以做个类比,让你实现判断鼠标单机还是双击,那么检测单击的时间会比双击要长。因为双击失效后才会进行单击判定。
同理手势识别不了了,其它才有机会处理,UIControl子类也类似,那么优先级如下所示:

触摸相关手势 > UIControl的子类 > TouchEvent

一般情况下,我们遇到的是手势触发了就不会继续转发事件了。
这就是为什么有人在UIButton中添加个tap手势看起来正常(别笑)。

事件分发机制应用

事件分发不同场景方法选择

  1. 更改事件分发流程,实现相关类的hitTest:withEvent:方法为佳。

  2. 扩大点击范围,覆写pointInside:withEvent:是个不错的选择。

  3. 解决一写如收起键盘等问题,可尝试直接发送事件。如:

    [[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
    
  4. 选择让父视图或者关联视图控制器处理事件可以这么写(虽然很少见有这么玩的):

    [button addTarget:nil action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
    

具体应用场景

实现自定义悬浮窗

根据响应链规则,我们能更好的设计一个自定义悬浮窗。

  1. 悬浮窗作为UIWindow的rootController存在
  2. 覆写pointInside:withEvent:判断事件所属UIWindow
  3. 完善自己的事件命中测试,实现视图层级管理

详情参加Flex写法。

模拟点击

通过了解分析事件分发过程,我们能很清楚的知道要实现模拟点击我们只需把点击事件发送给UIApplication单例的队列就可以了。

  1. 创建UIEvent对象。
  2. 发送UIEvent对象[[UIApplication sharedApplication] sendEvent:event]

统计与修改UITouch

  1. hook UIApplication类的- (void)sendEvent:(UIEvent *)event;方法
  2. 进行统计或修改

注:创建UITouch对象和对UITouch对象进行修改,可以参考kif-framework

参考资料

  1. flex
  2. kif-framework
  3. using responders and the responder chain to handle events
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • 重点参考链接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi阅读 4,410评论 0 15
  • 好奇触摸事件是如何从屏幕转移到APP内的?困惑于Cell怎么突然不能点击了?纠结于如何实现这个奇葩响应需求?亦或是...
    Lotheve阅读 56,841评论 51 598
  • 在iOS开发中经常会涉及到触摸事件。本想自己总结一下,但是遇到了这篇文章,感觉总结的已经很到位,特此转载。作者:L...
    WQ_UESTC阅读 5,995评论 4 26
  • 本质上是乡下人,他的根,他的魂不在城里,笨拙、迟钝的标签尽显。本是简单纯真的人,哪能适应城里人复杂狡诈的人际关系?...
    小小佘阅读 279评论 0 1
  • 一、概念 二、代码
    liyuhong阅读 206评论 0 0