首页 > 其他分享 >iOS事件的传递与响应

iOS事件的传递与响应

时间:2023-04-03 10:00:49浏览次数:48  
标签:touches iOS UIEvent 视图 传递 响应 事件 响应者

1.IOHIDEvent事件的传递

1当发生触摸屏幕等硬件事件的时候,会通过 IOKit.framework 产生一个 IOHIDEvent 对象

aIOKit.framework 是一个系统框架的集合,用来驱动一些系统事件。IOHIDEvent 中的 HID 代表 Human Interface Device,即人机交互驱动。

1然后系统通过 mach port(IPC 进程间通信) 将 IOHIDEvent 对象转发给 SpringBoard.app。

2SpringBoard.app 是 iOS 系统桌面 App,它只接收按键、触摸、加速、接近传感器等几种 Event。SpringBoard.app 会找到可以响应这个事件的 App,并通过 mach port(IPC 进程间通信) 将 IOHIDEvent 对象转发给这个 App。

3前台 App 主线程 Runloop 接收到 SpringBoard.app 转发过来的消息之后,触发对应的 mach port 的 Source1 回调 __IOHIDEventSystemClientQueueCallback()。

4Source1 回调内部将 IOHIDEvent 对象转化为 UIEvent, 触发了 Source0 回调__UIApplicationHandleEventQueue()。

5Soucre0 回调内部调用 UIApplication 的 +[sendEvent:] 方法,将 UIEvent 传给UIWindow。


传递流程图如下:

iOS事件的传递与响应_UIEvent


传递堆栈信息如下:

iOS事件的传递与响应_CGRectContainsPoint_02


找到UIWindow后,接下来需要做的就是传递UIEvent事件。



2.UIEvent事件传递

UIEvent事件传递大致可以分为三个阶段:

1Hit-Testing(寻找合适的 view)

2Recognize Gesture(响应手势)

3Response Chain(touch 事件传递, 响应事件)


2.1 Hit-Testing 碰撞检测(父视图到子视图)

1是否可响应事件

a是否开启用户交互

b是否 hidden

c是否 alph < 0.01

2手势发生的点是否在当前 view 内

3如果均为是,则倒着遍历子视图,递归判断子视图是否满足1、2两点。如果子视图均不满足,则表示自己则为最合适的响应者。

a倒着遍历子视图数组,是因为,最后添加的视图在最上方,最有可能是响应者,这样可以减少遍历次数

b如果最佳响应者是自己,但是自己不想处理,可以返回nil, 表示未找到最佳处理者,交给父视图处理。

c如果想不管查找结果如何,就是指定最佳响应者为某个视图,那么就直接返回那个视图。

d如果想增加视图的响应区域,可以获取当前视图的size,宽高增加后,再通过CGRectContainsPoint(touchRect, point)判断点是否在当前视图上。


碰撞检测的代码逻辑示例如下:


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    // 是否响应 touch 事件
    if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) return nil;
    
    // 点是否在 view 内
    if (![self pointInside:point withEvent:event]) return nil;
    
    for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
        CGPoint convertedPoint = [subview convertPoint:point fromView:self];
        // point 进行坐标转化,递归调用,寻找自视图,直到返回 nil 或者 self
        UIView *hitTestView = [subview hitTest:convertedPoint withEvent:event];
        if (hitTestView) {
            return hitTestView;
        }
    }
    return self;

2.3 Gesture Recognizer

Gesture Recognizer(手势识别器)是系统封装的一些类,用来识别一系列的常见手势,例如点击、长按等。

在上一步中确定了合适的 View 之后,UIWindow 会首先将 touches 事件先传递给 Gesture Recognizer,再传递给视图自己的touch事件。这一点可以通过自定义一个手势,并将手势添加到 View 上来验证。你会发现会先调用自定义手势中的一系列 touches 方法,再调用视图自己的一系列 touches 方法。


如果是UIControl,同时添加了手势和target-action事件,会先响应手势,并且发送一个touchCancelled事件,中断事件响应的传递,也就是target-action事件不会执行。但是对于常见的一些UIControl的子类,苹果内部做了处理,只响应target-action事件,不会触发手势。

iOS事件的传递与响应_UIEvent_03

2.2 响应者链 touch 事件传递(子视图到父视图)

当确定哪个视图是最佳响应者后,系统会自动触发视图的一系列的 touch 事件。

  • touch 事件如果没有被视图重写,默认操作是将事件顺着响应者链条向上传递,将事件传递给上一个响应者进行处理。这个过程与碰撞检测相反,是由子视图传递给父视图。
  • 如果重写,要注意写[super touch*],不然就会使响应者链就此终止,不会再向上传递

响应者链的事件传递过程:

  1. 如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递给控制器;
  2. 如果当前view不是控制器的view,那么父视图就是当前view的上一个响应者,事件就传递给它的父视图
  3. 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
  4. 如果window对象也不处理,则其将事件或消息传递给UIApplication对象
  5. 如果UIApplication也不能处理该事件或消息,则将其丢弃
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
 
/**
  iOS 9.1 增加的 API,当无法获取真实的 touches 时,UIKit 会提供一个预估值,并设置到 UITouch 对应的 estimatedProperties 中监测更新。当收到新的属性更新时,会通过调用此方法来传递这些更新值。
  
  eg: 当使用 Apple Pencil 靠近屏幕边缘时,传感器无法感应到准确的值,此时会获取一个预估值赋给 estimatedProperties 属性。不断去更新数据,直到获取到准确的值
  */
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);




标签:touches,iOS,UIEvent,视图,传递,响应,事件,响应者
From: https://blog.51cto.com/u_15566227/6165570

相关文章

  • 【ChatGPT答】频率特性、频谱特性、幅频特性的区别,传递函数和增益的区别
    仅供参考。频率特性频率特性是指一个系统或信号在不同频率下的性质,通常用于描述系统或信号的频率响应。在信号处理中,频率特性是对信号在频率域中的分布和特征进行描述的一种方式,也是理解信号在不同频率下的行为的基础。具体来说,频率特性包括以下几个方面:频率响应:一个系统对......
  • 怎样实现纯前端百万行数据秒级响应
    前端表格控件SpreadJS推出了新的功能集算表功能。集算表(TableSheet)是一个具备高性能渲染、数据绑定功能、公式计算能力的数据表格,通过全新构建的关系型数据管理器结合结构化公式,在高性能表格的基础上提供排序、筛选、样式、行列冻结、自动更新、单元格更新等功能。 什么是集算......
  • ios开发框架
    大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博、微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的。如今,网络编程越来越普遍,孤立的应用通常是没有生命力的。今天就会给大家介绍这部分内容:Web请求和响应使用代理方法简化请求方法图片......
  • java -- static, 内部类, 权限, 参数传递
    static关键字static是静态修饰符,一般修饰成员。被static修饰的成员属于类,不属于单个这个类的某个对象。static修饰的成员被多个对象共享。static修饰的成员属于类,但是会影响每一个对象。被static修饰的成员又叫类成员,不叫对象的成员。static特点被static修饰的成员变量属于类,不......
  • 【IOS】IOS7 UI适配
    试着编译了一下刚刚完成的几个应用,还好问题不大,半个小时的时间都适配好了,然后改了下几个新出现的warning。过几天等空了,要把IOS7的更新的特性好好看一下 http://www.cocoachina.com/newbie/basic/,记录一下。Xcode5正式版的下载地址:http://adcdownload.apple.com/Developer_Tool......
  • Swagger knife4j响应参数不显示
    问题描述 解决方法  一定要加上@Data   接口要返回实体类型  参考链接【1】https://gitee.com/xiaoym/knife4j/issues/I2CY7K......
  • HTTP响应状态码拆解
    HTTP响应状态码拆解状态码:是用以标识网页服务器超文本传输协议响应状态的3位数字代码    常用HTTP状态码         HTTP状态码详解......
  • 响应式网页设计
    学习响应式网页设计需要以下几个步骤:学习基本的HTML和CSS知识,了解网页布局和样式设置。熟悉CSS媒体查询语法和使用方法,媒体查询是响应式网页设计的核心,通过媒体查询可以根据屏幕尺寸、分辨率等不同因素来设置不同的CSS样式,从而实现响应式效果。学习响应式网格系......
  • 3·1HTTP协议特点、3·2详解URL与URI的区别与联系、3·3HTTP报文结构分析、3·4HTTP请
     HTTP协议特点支持客户/服务器模式客户/服务器模式工作的方式是由客户端向服务器发出请求,服务器端响应请求,并进行相应服务简单快速 客户端向服务器请求服务时,只需传输请求方法和路径 请求方法常用的有GET、HEAD、POST。每种方法规......
  • 低通和高通电路频率响应分析
    ●低通电路\(\qquad\)●传递函数:\(A_v=\frac{1}{1+jωRC},令f_H=\frac{1}{2πRC},A_v=\frac{1}{1+j\frac{f}{f_H}}\)\(\qquad\)●幅频特性:\(|A_v|=\frac{1}{\sqrt{1+(\frac{f}{f_H})^2}}\)\(\qquad\qquad\)●当\(f<<f_H\)时,\(|A_v|=\frac{1}{\sq......