美文网首页
iOS事件传递与响应原理

iOS事件传递与响应原理

作者: RiverSea | 来源:发表于2018-10-29 16:28 被阅读93次
iOS事件传递与响应原理.png

iOS 中的事件可以分为3大类:触摸事件、加速计事件、远程控制事件,本文仅以 iOS 中的触摸事件为例进行讨论,主要是自己很少用另外两个O(∩_∩)O。

在 iOS 中不是任何对象都能处理事件的,只有继承自 UIResponder 的对象才能接收并处理事件,我们称之为“响应者对象”。以下都是继承自 UIResponder 的,所以都能接收并处理事件:UIApplication、UIView、UIViewController,继承自他们的类自然也具有这个能力:

UIResponder.png

1. 触摸事件处理的整体过程

  • 触摸屏幕发生触摸事件后,系统会将该事件添加到 UIApplication 管理的事件队列 (FIFO) 中。

  • UIApplication 会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。

  • 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。

  • 找到合适的视图控件后,就会调用视图控件的 touches 方法来作具体的事件处理。(touches默认做法是把事件顺着响应者链条向上抛,如下)

// 只要点击控件, 就会调用touchBegin, 如果没有重写这个方法, 自己处理不了触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    // 默认会把事件传递给上一个响应者,上一个响应者是父控件,交给父控件处理
    [super touchesBegan:touches withEvent:event];
    // 注意不是调用父控件的touches方法,而是调用父类的touches方法
    // super是父类 superview是父控件
}

2. 事件的传递

  • 触摸事件的传递是从父控件传递到子控件,也就是 UIApplication -> window -> 寻找处理事件最合适的view。

  • 注意:如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件。

2.1 应用如何找到最合适的控件来处理事件?

1.首先判断主窗口(keyWindow)自己是否能接受触摸事件;

2.判断触摸点是否在自己身上;

3.子控件数组中 “从后往前” 遍历子控件,重复前面的两个步骤;
(之所以会采取 “从后往前” 遍历子控件的方式寻找最合适的view只是为了做一些循环优化,因为后添加的view在上面,可以降低循环次数)

4.view,比如叫做 fitView,那么会把这个事件交给这个 fitView,再遍历这个fitView的子控件,直至没有更合适的view为止;

5.如果没有符合条件的子控件,那么就认为自己最合适处理这个事件,也就是自己是最合适的view。

2.2 查找最合适 view 的底层原理

此处会用到两个重要的方法:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
  • 只要事件一传递给 view,就会调用它自己的 hitTest:WithEvent: 方法,这个方法会寻找并返回 能够响应事件的那个最合适的 view。

  • 事件会先传递给这个 view,随后调用 hitTest:WithEvent: 方法,在 hitTest:WithEvent: 方法里边,再来 判断此 view 能不能处理事件(userInteractionEnabled),及触摸点在不在此 view 上 (pointInside:withEvent:)。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    // 1.判断下窗口能否接收事件
    if (self.userInteractionEnabled == NO || self.hidden == YES ||  self.alpha <= 0.01) return nil;
    // 2.判断下点在不在窗口上
    if ([self pointInside:point withEvent:event] == NO) return nil;
    // 3.从后往前遍历子控件数组
    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) {
            // 如果能找到最合适的view
            return fitView;
        }
    }
    // 4.没有找到更合适的view,也就是没有比自己更合适的view
    return self;
}

2.3 UIView 不能接收触摸事件的 3 种情况

  • 不允许交互:userInteractionEnabled = NO
  • 隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件
  • 透明:如果设置一个控件的 透明度 < 0.01,会直接影响子控件的透明度,alpha:0.0 ~ 0.01 为透明。

3. 事件的响应

iOS左_&_OSX右_responder_chain.png

1.首先看 initial view 能否处理这个事件,如果不能则会将事件传递给其上级视图(inital view 的 superView);

2.如果上级视图仍然无法处理则会继续往上传递;一直传递到视图控制器 view controller,首先判断视图控制器的根视图 view 是否能处理此事件;如果不能则接着判断该视图控制器能否处理此事件,如果还是不能则继续向上传 递;(对于左图 ViewController 本身还在另一个视图控制器中,则继续交给父视图控制器的根视图,如果根视图不能处理则交给父视图控制器处理);

3.一直到 window,如果 window 还是不能处理此事件则继续交给 application 处理,如果最后 application 还是不能处理此事件则将其丢弃。

在事件的响应中,如果某个控件实现了touches...方法,则这个事件将由该控件来处理,如果调用了 [super touches….];就会将事件顺着响应者链条往上传递,传递给上一个响应者;接着就会调用上一个响应者的 touches…. 方法。

3.1 响应者链条、响应者对象

响应者链条 (responder chain): 在iOS程序中无论是最后面的 UIWindow 还是最前面的某个按钮,它们的摆放是有前后关系的,一个控件可以放到另一个控件上面或下面,那么用户点击某个控件时是触发上面的控件还是下面的控件呢,这种先后关系构成一个链条就叫“响应者链”。也可以说,响应者链是由多个响应者对象连接起来的链条。

响应者对象 (responder): 能处理事件的对象,也就是继承自 UIResponder 的对象。

3.2 如何做到一个事件多个对象处理:

因为系统默认做法是把事件上抛给父控件,所以可以通过重写自己的touches方法和父控件的touches方法来达到一个事件多个对象处理的目的。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    // 1. 自己先处理事件...
    NSLog(@"do somthing...");
    // 2. 再调用系统的默认做法,再把事件交给上一个响应者处理
    [super touchesBegan:touches withEvent:event]; 
}

参考

相关文章

  • ios 事件传递和响应

    史上最详细的iOS之事件的传递和响应机制-原理篇iOS触摸事件传递响应之被忽视的手势识别器工作原理手势事件中can...

  • 初识iOS事情处理机制

    参考:史上最详细的iOS之事件的传递和响应机制-原理篇iOS触摸事件全家桶史上最详细的iOS之事件的传递和响应机制...

  • iOS 响应链

    iOS开发 - 事件传递响应链iOS 响应者链,事件的传递事件传递之响应链Cocoa Touch事件处理流程--响...

  • iOS事件分发机制分析

    前言 iOS事件的传递与响应是一个重要的话题,此文将结合苹果官方的文档对事件的传递与响应原理及应用实践做一个比较完...

  • UI事件传递&事件响应

    响应链工作原理 点击某一控件到其响应相关事件其实是分为两步:事件的传递与事件的响应 事件分发与传递:自上而下 事件...

  • iOS事件传递与响应原理

    iOS 中的事件可以分为3大类:触摸事件、加速计事件、远程控制事件,本文仅以 iOS 中的触摸事件为例进行讨论,主...

  • 面试知识集-UI事件传递,图像显示,性能优化,离屏渲染

    UIView与CALayer关系 事件传递与视图响应链 事件传递与视图响应链 图像显示原理 UI卡顿掉帧分析及解决...

  • 深入浅出iOS事件机制

    深入浅出iOS事件机制事件传递:响应链事件传递响应链

  • iOS 触摸事件与响应理解

    参考文章: iOS触摸事件的流动 iOS触摸事件的传递与响应 UIViewController UIAppli...

  • 史上最详细的iOS之事件的传递和响应机制-实践篇

    前言 之前我已经通过《史上最详细的iOS之事件的传递和响应机制-原理篇》比较详细的介绍过了事件的响应和传递的一些原...

网友评论

      本文标题:iOS事件传递与响应原理

      本文链接:https://www.haomeiwen.com/subject/xrnswftx.html