• iOS事件传递链与响应链


    ✅作者简介:大家好我是瓜子三百克,励志成为全栈工程师的一枚程序猿,也是喜欢在学习和开发中记录笔记的小白博主!
    📃个人主页:瓜子三百克的主页
    🔥系列专栏:iOS
    💖如果觉得博主的文章还不错的话,请点赞👍+收藏⭐️+留言📝支持一下博主哦🤞

    当我们在手机上点击、滑动等屏幕操作进入到相应的页面,手机是如何区分相应指令并响应的呢?其中又是经历了怎样的过程呢?这里涉及到了事件响应链。

    1、事件链

    如下图所示,用户点击屏幕时,首先UIApplication对象先收到该点击事件,再依次传递给它上面的所有子view,直到传递到最上层,即UIApplication ——> UIWindow ——> RootViewController ——> View ——> Button,即传递链
    而反之Button ——> View ——> RootViewController ——> UIWindow ——> UIApplication则称为响应链
    简单总结,事件链包含传递链和响应链,事件通过传递链传递上去,通过响应链找到相应的UIResponse

    在这里插入图片描述

    2、传递链

    由系统向离用户最近的view传递,如上图所示。具体流程如下:

    1、用户在点击屏幕。
    2、系统将点击事件加入UIApplication管理的消息队列中。
    3、UIApplication会从消息队列中取出该事件传递UIWindow对象;
    4、在UIWindow中调用方法hitTest:withEvent:返回最终相应的view

    1、在hitTest:withEvent:方法中调用pointInside:withEvent:判断当前点击的点是否在UIWindow内部;
    2、如若返回yes,则倒序遍历其子视图找到最终响应的子view;
    3、如果最终返回一个view,那么即为最终响应view并结束事件传递,如果无值返回则将UIWindow作为响应者。见下图:

    在这里插入图片描述其中核心方法如下:

    // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
    - (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;   
    // default returns YES if point is in bounds
    - (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;   
    
    • 1
    • 2
    • 3
    • 4

    方法hitTest:withEvent:用来获取最终响应事件的view。
    方法pointInside:withEvent:,用来判断点击的位置是否在视图范围内。
    以下为UIView不接受事件处理的情况:

    view.hidden = YES;
    view.userInteractionEnabled = NO;
    view.alpha < 0.01;
    
    • 1
    • 2
    • 3

    3、响应链

    由离用户最近的view向系统传递。如下所示:
    在这里插入图片描述响应链处理具体流程:

    1、若view的 viewcontroller 存在,则将该事件传递给其viewcontroller响应;如若不存在,则传递给其父视图;
    2、若view的最顶层不能处理事件,则传递给UIWindow进行处理;
    3、若UIWindow不能处理,则传递给UIApplication;
    4、若UIApplication不能处理,则将该事件丢弃。

    4、示例代码

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        UIView *touchView = self;
        // 1、判断 self 是否可以接受事件处理
        // 2、判断 self 是否在点击区间
        if (self.hidden == NO
            && self.alpha >= 0.01
            && [self pointInside:point withEvent:event]) {
            // 3、便利所有子view
            for (UIView *subView in self.subviews) {
                // 4、获取点击的点在子view上的坐标
                CGPoint subPoint = [subView convertPoint:point fromView:self];
                // 5、递归获取点击响应的子view
                UIView *subTouchView = [subView hitTest:subPoint withEvent:event];
                if (subTouchView) {
                    touchView = subTouchView;
                    break;;
                }
            }
        } else {
            // 不接受事件处理直接返回 nil;
            touchView = nil;
        }
        return touchView;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    优秀讲解推荐: https://blog.csdn.net/songzhuo1991/article/details/122667980


    🏆结束语🏆
    如 果 觉 得 我 写 的 内 容 对 您 有 帮 助 的 话 : \textcolor{green}{如果觉得我写的内容对您有帮助的话:} :
    欢 迎 点 赞 ✌ , 收 藏 ✌ , 加 关 注 ✌ 哦 , 谢 谢 ! ! \textcolor{green}{欢迎点赞✌,收藏✌,加关注✌哦,谢谢!!}

  • 相关阅读:
    研究生数学建模竞赛——近五年赛题分析以及数据分析类赛题优秀论文分享
    性能测试度量指标
    金仓数据库KingbaseES安全指南--5.2. 数据完整性保护
    使用NNO区域进行色偏检测
    安科瑞高等学校校园建筑节能监管系统建设
    DayDayUp:计算机技术与软件专业技术资格证书之《系统集成项目管理工程师》课程讲解之十大知识领域之4核心—成本进度管理
    python-web开发[20]之开发小结
    GPU 直通 & vGPU:超融合为 GPU 应用场景提供高性能支持
    【二叉树-困难】124. 二叉树中的最大路径和
    贝叶斯公式——假阳性问题
  • 原文地址:https://blog.csdn.net/weixin_38633659/article/details/125030427