iOS学习记录iOS进阶相关iOS 开发

浅析iOS中事件的产生与响应过程

2016-10-03  本文已影响162人  BWLi420

想要学习事件的产生与响应过程首先要了解什么是响应者对象,什么是响应者链条

响应者对象:继承了UIResponder的对象称之为响应者对象,也就是能处理事件的对象。

响应者链条:是由多个响应者对象连接起来的链条。

其次,并不是所有的控件都可以接收事件,在以下五种情况下控件不能接收事件:

  1. 不接收用户交互时不能够处理事件

    userInteractionEnabled = NO;
    注意:UIImageView的userInteractionEnabled默认就是NO


事件是怎样产生与传递的?

当用户点击屏幕后会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中。UIApplication会从事件队列中取出最前面的事件,并将事件传递给先发送事件给应用程序的主窗口以便处理,主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件。

事件传递示例

怎么寻找处理事件最合适的视图 view ?

  1. 先判断自己是否能够接收触摸事件,如果能再继续往下判断;

在寻找最合适的视图 view 中,需要使用到 hitTestPointInside 两个方法。

hitTest 方法与 PointInside 方法

  1. hitTest 方法
    -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
        - 作用:寻找最适合的View
        - 参数:当前手指所在的点,产生的事件
        - 返回值:返回谁,谁就是最适合的View
        - 只要传递给一个控件时,就会调用这个控件的 hitTest 方法
    
        - 作用:判断point在不在方法调用者上
        - point:必须是方法调用者的坐标系
        - hitTest方法底层会调用这个方法,判断点在不在控件上
- hitTest 方法的底层实现

    ① 判断当前控件能不能接收事件
    
    ```
    if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) 
         return  nil;
    ```
    ② 判断触摸点在不在当前的控件上
    
    ```
    if(![self pointInside:point withEvent:event])
        return nil;
    ```
    ③ 从后往前遍历自己的子控件
    
    ```
int count = (int)self.subviews.count;
for (int i = count - 1; i >= 0;i-- ) {
        
     UIView *childV = self.subviews[i];
     //把当前坐标系上的点转换成子控件坐标系上的点
     CGPoint childP = [self convertPoint:point toView:childV];
     //判断自己的子控件是不是最适合的View
     UIView *fitView = [childV hitTest:childP withEvent:event];
     //如果子控件是最适合的View,直接返回
     if (fitView) {
          return  fitView;
      }
     //否则自己就是最适合的View
     return self;
}
    ``` 
    
#### 事件产生、传递与响应的完整过程
1. 当用户点击屏幕后会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中;
2. UIApplication会从事件队列中取出最前面的事件,并将事件传递给先发送事件给应用程序的主窗口以便处理;
3. 主窗口会调用 hitTest 方法寻找最适合的视图控件,找到后就会调用视图控件的 touches 方法来做具体的事情;
4. 当调用 touches 方法,它的默认做法会将事件顺着响应者链条往上传递;
5. 传递给上一个响应者,接着就会调用上一个响应者的touches方法。
![响应者链条示意图](http:https://img.haomeiwen.com/i2997426/d5b481373f9f4834.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

#### 如何寻找上一个响应者?
1. 如果当前的View是控制器的View,那么控制器就是上一个响应者
2. 如果当前的View不是控制器的View,那么它的父控件就是上一个响应者
3. 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
4. 如果window对象也不处理,则其将事件或消息传递给UIApplication对象
5. 如果UIApplication也不能处理该事件或消息,则将其丢弃
上一篇下一篇

猜你喜欢

热点阅读