「OC」iOS事件处理流程

news2024/11/15 10:01:07

「OC」初识iOS事件处理流程

文章目录

  • 「OC」初识iOS事件处理流程
    • 触摸事件
    • 触摸事件的响应周期
    • 事件 响应者
      • UIEvent
      • UITouch
      • UIResponder
    • 触摸流程
      • 系统响应阶段
      • APP响应阶段
        • 寻找最佳响应者
      • 构成响应链
    • 寻找最佳响应者和响应链的区别
    • 总结
    • 参考资料

触摸事件

iOS的事件有好几种:Touch Events(触摸事件)、Motion Events(运动事件,比如重力感应和摇一摇等)、Remote Events(远程事件,比如用耳机上得按键来控制手机),其中最常用的应该就是Touch Events了,基本存在于每个app的每个地方

触摸事件的响应周期

uitouchflow.png

事件 响应者

在学习之前,还需要将基本的概念了解清楚

UIEvent

UIEvent即为事件,事件一共被分为三类,包括触摸事件(Touch Events对应就是UITouch)、运动事件(Motion Events)、远程控制事件(Remote Control Events)。

触摸的目的是生成触摸事件供响应者响应,一个触摸事件对应一个UIEvent对象,其中的 type 属性标识了事件的类型(即三种不同的时间类型)。

当我们app获取到触摸事件的时候,就会将event放置到一个事件队列之中(先触发的事件先执行,符合队列先进先出的特点)

UITouch

一个手指一次触摸屏幕,就对应生成一个UITouch对象。多个手指同时触摸,生成多个UITouch对象。

多个手指先后触摸,系统会根据触摸的位置判断是否更新同一个UITouch对象。若两个手指一前一后触摸同一个位置(即双击),那么第一次触摸时生成一个UITouch对象,第二次触摸更新这个UITouch对象(UITouch对象的 tap count 属性值从1变成2);若两个手指一前一后触摸的位置不同,将会生成两个UITouch对象,两者之间没有联系。

每个UITouch对象记录了触摸的一些信息,包括触摸时间、位置、阶段、所处的视图、窗口等信息。

手指离开屏幕一段时间后,确定该UITouch对象不会再被更新将被释放。

在UIEvent之中使用以下方法可以获得UIEvent的touch信息:

NSSet *touches = [event allTouches];
for (UITouch *touch in touches) {
    // 访问每个 UITouch 对象的属性
    CGPoint location = [touch locationInView:view];
    NSTimeInterval timestamp = [touch timestamp];
    // 其他属性...
}

UIResponder

每个响应者都是一个UIResponder对象,即所有继承于自UIResponder的对象,本身都具备响应事件的能力。因此以下类的实例都是响应者:

  • UIView
  • UIViewController
  • UIApplication
  • AppDelegate

在有关触摸的内容,我们使用以下的方法

//手指触碰屏幕,触摸开始
- (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. IOKit.framework封装整个触摸事件为IOHIDEvent对象
  2. OKit.framework通过IPC将事件转发给SpringBoard.app
  3. IOKit将触摸事件封装成一个IOHIDEvent对象,并通过mach port传递给SpringBord进程

mach port是各个进程的端口,各进程通过它来进行进程间通信
SpringBord是一个系统进程,可以理解为桌面系统。它用来统一管理系统接收到的触摸事件

APP响应阶段

前面的阶段,是通过硬件结合来进行的,接下来的阶段就是通过app来找到点击时,手指停留在view之中的位置,我们还需要将时事件传递给具体被点击的View上。 我们要处理这个问题,就是需要使用响应链。

img

寻找最佳响应者

在UIView之中存在以下两个方法

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;  //返回触发点击的view
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;  //判断坐标在哪个view的管辖范围内

通过这两个方法,通过上面图片给出的流程,不断循环追溯到准确的响应子视图 ,第二个方法是包含在第一个方法之中的。

这一过程主要来确定由哪个视图来首先处理 UITouch 事件。当你点击一个 view,事件传到 UIWindow 这一步之后,会去遍历 view 层级,直至找到那个合适的 view 来处理这个事件,这一过程也叫做 Hit-Testing。而在传递至UIWindow之前,UIApplication先将事件通过 sendEvent: 传递给事件所属的window,window同样通过 sendEvent: 再将事件传递至view之中。

系统会根据添加 view 的前后顺序,确定 view 在 subviews 数组中的顺序。然后根据这个顺序将视图层级转化为图层树,针对这个树,使用倒着进行前序深度遍历的算法,进行遍历。

前序深度遍历的具体流程如下:

  • 如果点不在这个视图内,则去遍历其他视图。
  • 如果点击在这个视图内,但是其还有子视图,那么将事件传递给子视图,并且调用子视图的 [hitTest:withEvent:].
  • 如果点击在这个视图内,并且这个视图没有子视图,那么 return self,即它就是那个最合适的视图。
  • 如果点击在这个视图内,并且这个视图没有子视图,但是不想作为处理事件的 view,可以 return nil,事件由父视图处理。

注:以下三种情况UIView以及其子View的hitTest(_:with:)不会被调用,而且子UIView不接收任何触摸事件

userInteractionEnabled = NO
hidden = YES
alpha = 0.0~0.01之间(透明度<0.01即为透明)

UIImageViewuserInteractionEnabled默认为NO,因此UIImageView以及它的子控件默认是不接收触摸事件的。

通过以上内容,我们可以仿照一个相关的方法hitTest:withEvent:,以下直接照抄大佬给出的内容:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    //3种状态无法响应事件
     if (self.userInteractionEnabled == NO || self.hidden == YES ||  self.alpha <= 0.01) return nil; 
    //触摸点若不在当前视图上则无法响应事件
    if ([self pointInside:point withEvent:event] == NO) return nil; 
    //从后往前遍历子视图数组 
    int count = (int)self.subviews.count; 
    for (int i = count - 1; i >= 0; i--) 
    { 
        // 获取子视图
        UIView *childView = self.subviews[i]; 
        // 坐标系的转换,把触摸点在当前视图上坐标转换为在子视图上的坐标
        CGPoint childP = [self convertPoint:point toView:childView]; 
        //询问子视图层级中的最佳响应视图
        UIView *fitView = [childView hitTest:childP withEvent:event]; 
        if (fitView) 
        {
            //如果子视图中有更合适的就返回
            return fitView; 
        }
    } 
    //没有在子视图中找到更合适的响应视图,那么自身就是最合适的
    return self;
}

构成响应链

最佳响应者的最佳,其实就是这个UIResponder对象具有响应对应事件的最高权限,每一个响应者对象(UIResponder对象)都有一个 nextResponder 方法,用于获取响应链中当前对象的下一个响应者。

  • 若视图是控制器的根视图,则其nextResponder为控制器对象;否则,其nextResponder为父视图。
  • UIViewController
    若控制器的视图是window的根视图,则其nextResponder为UIWindow对象;若控制器是从别的控制器present出来的,则其nextResponder为presenting view controller。
  • UIWindow
    nextResponder为UIApplication对象。
  • UIApplication
    若当前应用的app delegate是一个UIResponder对象,且不是UIView、UIViewController或app本身,则UIApplication的nextResponder为app delegate。

通过以上的方式我们就可以通过寻找nextResponder将响应链完整的构建出来。

响应者对于事件的拦截以及传递都是通过 touchesBegan:withEvent: 方法控制的,该方法的默认实现是将事件沿着默认的响应链往下传递。响应者链存在的意义为提供一种机制,让未被直接交互的对象也有机会处理事件,增加了事件处理的灵活性。

img

寻找最佳响应者和响应链的区别

  • 寻找最佳响应者:
    • 从最底层的视图开始,自下而上地检查视图层级。
    • 使用hitTest:withEvent:方法来确定哪个视图包含了触摸点。
    • 考虑视图的属性,如是否隐藏、是否启用用户交互等。
  • 响应者链:
    • 从最佳响应者开始,沿着预定义的路径向上传递。
    • 通常的路径是:UIView → UIViewController → UIWindow → UIApplication → UIApplicationDelegate。

总结

以上就是对触摸事件以及响应者链的学习内容,接下来还有UIResponder、UIGestureRecognizer、UIControl这个几个触发响应的优先级,以及响应事件内部的深入探究,由于篇幅我们便将剩下的内容留到下一篇博客吧。

参考资料

01 触摸事件传递

iOS事件处理

iOS——事件、响应链和传递链

iOS触摸事件全家桶

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2108267.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PDF到CAD转换:四大实用工具指南!

将纸质图纸或PDF文件转化为可编辑的CAD文件是一项基本技能。无论是为了更好地进行团队协作&#xff0c;还是为了简化设计流程&#xff0c;找到一个合适的PDF转CAD工具都是至关重要的。本文将深入探讨几款主流工具的功能特色&#xff0c;并结合实际使用经验分享个人见解。 福昕…

机器之心 | 预训练无需注意力,扩展到4096个token不成问题,与BERT相当

本文来源公众号“机器之心”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;预训练无需注意力&#xff0c;扩展到4096个token不成问题&#xff0c;与BERT相当 本文提出了双向门控 SSM&#xff08;BiGS&#xff09;模型&#xff0c;…

vben admin里面换行useTable里面的columns

{title: 标题,dataIndex: systemName,width: 300, minWidth: 300,customRender: ({ text }: { text: string }) > {return ${text};},}, customRender: ({ text }: { text: string }) > { return ${text}; },这行代码. 方法② ellipsis: false,加这个进去&#xff…

半导体产业核心环节有哪些?2024年中国半导体产业研究报告大揭秘!

半导体指常温下导电性能介于导体与绝缘体之间的材料。半导体应用在集成电路、消费电子、通信系统、光伏发电、照明应用、大功率电源转换等领域。半导体产业经济则是指以半导体产品为核心的经济活动&#xff0c;包括芯片设计、制造、封装测试及应用等。它是全球经济的支柱&#…

Linux 硬件学习 s3c2440 arm920t蜂鸣器

1.查找手册时钟图&#xff0c;输入12m想要通过pll得到400m的信号 2.对比pll值&#xff0c;找到最近的为405&#xff0c;得到pll中mdiv为127&#xff0c;pdiv为2&#xff0c;sdiv为1 3.想要得到fclk400&#xff0c;hclk100&#xff0c;pclk50&#xff0c;对比分频比例&#xff0…

Unet改进24:添加DualConv||轻量级深度神经网络的双卷积核

本文内容:在不同位置添加DualConv 目录 论文简介 1.步骤一 2.步骤二 3.步骤三 4.步骤四 论文简介 卷积神经网络(CNN)架构通常对内存和计算要求很高,这使得它们在硬件资源有限的嵌入式系统中不可行。 我们提出了双卷积核(DualConv)来构建轻量级深度神经网络。DualConv结…

亚马逊云科技 Gen BI 2024-09-04 上海站QuickSight

机缘 我又来了&#xff0c;感觉不上班比上班还要忙 天天像特种工一天&#xff0c;今天有度过的充实的一天&#xff0c;上午去图书馆&#xff0c;下午去了 亚马逊云科技 Gen BI 技术体验日 。 具体照片可以去 这里看 哈哈&#xff0c;这个就是我了 商业智能的趋势 根据艾瑞咨…

WildCard平台:什么是 ChatGPT 随心用?什么是 Claude 随心用?什么是随心用全能套餐?

最近胖虎收到很多私信都在询问&#xff0c;很多人搞不清楚什么是 ChatGPT 随心用&#xff1f;什么是 Claude 随心用&#xff1f;什么是随心用全能套餐&#xff1f;下面就对三种套餐做了全面的QA解答。 如果想直接使用随心用&#xff0c;或者订阅ChatGPT&#xff0c;或者支付 C…

示波器基础知识汇总(1)

系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 前言1、电子信号2、波属性①、幅度②、相移③、周期④、频率⑤、波形正弦波方波/矩形波三角波/锯齿波脉冲复合波 3、信…

YOLOv9模型训练或测试过程中,无法打印模型的GFLOPs

项目场景&#xff1a; 在YOLOv9模型的改进中&#xff0c;常常需要替换一些模块来提高模型的精度。但在评价模型大小规模的时候需要根据模型的参数量、计算量进行评定&#xff0c;一般在模型的训练文件train.py&#xff0c;或者是test.py还有models/yolo.py都会输出这些数据。 …

idea单元测试报错找不到主类

报错截图 主要是单测中没有配置类 在下面的command line 中选择jar manifest 因为条参数过长&#xff0c;这里设置只使用主类 详细解释见&#xff1a; https://www.jianshu.com/p/8322b3b17040

Web开发的艺术:C#开发中实现代码简洁性与规范性的终极指南

一、变量的要求 变量名 1.简短有意义: 合适: student_count&#xff0c;student_ids&#xff0c;student_enable_list, water_price 不合适: numberOfItemsInTheCart, totalPriceOfTheOrderInTheShoppingCart,temp, data,list 2.变量名之间不要太像: 合适: totalAmount, disc…

传统CV算法——边缘检测算法Canny算法实战

Canny 算法 边缘&#xff1a;我的理解是在图像处理的过程中&#xff0c;针对我们图像处理的过程中&#xff0c;梯度变化以较大的地方能够让我们能够快速辨识&#xff0c;针对一个人脸&#xff0c;脸上有一些平滑的地方&#xff08;没错我针对美颜的&#xff09;&#xff0c;与…

JavaScript 条件分支语句if...else

if 语句 只有当指定条件为 true 时&#xff0c;该语句才会执行代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name…

Introduction to Deep Learning with PyTorch

1、Introduction to PyTorch, a Deep Learning Library 1.1、Importing PyTorch and related packages import torch# supports: ## image data with torchvision ## audio data with torchaudio ## text data with torchtext 1.2、Tensors: the building blocks of network…

磁盘加密工具 | VeraCrypt v1.26.15 绿色版

VeraCrypt 是一个开源项目&#xff0c;旨在提供强大的加密解决方案&#xff0c;以创建和管理加密的磁盘分区和加密容器。它继承了著名的加密软件 TrueCrypt 的特性&#xff0c;并在此基础上进行了扩展和改进。 主要特性 1. 高级加密算法 VeraCrypt 支持多种加密算法&#xf…

假如你是HR,你怎么招「游戏策划」?

你是一名从业十余年&#xff0c; 拥有丰富面试经历、掌握多种话术的 资深游戏行业人事。 想知道策划岗位该怎么入行可点击蓝链 你不满足于在名不见经传的小企业 拿一份凑合过的薪资&#xff0c; 于是你成功跳槽来到国内顶级游戏大厂“猪厂”&#xff0c; 并且接手了你的…

Redis集群技术1——nosql简述

一、关系型数据库和 NoSQL 数据库 1.1 数据库主要分为两大类&#xff1a;关系型数据库与 NoSQL 数据库 关系型数据库&#xff0c;是建立在关系模型基础上的数据库&#xff0c;其借助于集合代数等数学概念和方法来处理数据库 中的数据主流的 MySQL、Oracle、MS SQL Server 和 …

谷歌排名SEO优化#蜘蛛池软件(搜索大客户)

谷歌排名SEO优化#蜘蛛池软件&#xff08;搜索大客户&#xff09; 如何检测你的网站是否能被谷歌搜索引擎蜘蛛抓取 通过一个工具快速检测你的网站&#xff0c;是否能被谷歌搜索引擎&#xff0c;bing搜索引擎的蜘蛛爬取收录。网站是否能被蜘蛛抓取收录是谷歌SEO的基础&#xff0…

C_深入理解指针(五) —— sizeof和strlen的对比、数组和指针笔试题解析、指针运算笔试题解析

目录 一、sizeof和strlen的对比 1、sizeof 2、strlen 3、sizeof 和 strlen的对比 二、数组和指针笔试题解析 1、⼀维数组 重点学习代码&#xff1a;sizeof与一维整型数组类型 2、字符数组 代码1&#xff1a;sizeof与字符数组类型 代码2&#xff1a;strlen与字符数组类…