iOS - 事件的产生和传递

作者:Mitchell 

一、响应者对象

  • 在iOS中并不是任何对象都能处理事件,只有继承了UIResponder的对象才能接受并处理时间,称为“响应者”。
  • UIApplication、UIViewController、UIView都继承自UIResponder,它们都能是响应者对象,处理事件。

二、 事件传递的顺序

  • 1、先将事件对象由下往上传递(由父控件传递给子控件),找到最合适的控件来处理这个事件,如果view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图。
  • 2、调用最合适的控件的 touches 方法,在视图层次结构的最顶级视图,如果也不能处理收到的事件或者消息,则将时间或消息传递给window对象进行处理。
  • 3、如果调用了 [super touches] 就会将事件顺着响应者链条往上传递,传递给上一个响应者,如果window对象也不处理,则其将时间活消息传递给UIApplication对象。
  • 4、接着会调用上一个响应者的 touches 方法。如果UIApplication也不能处理该事件或消息,则将其丢弃。
  • 事件传递顺序:事件->UIApplication ->UIWindow (之后会寻找最合适的view)->rootView-> rootView子控件... (直到寻找到最合适的view来触发事件)

三、如何判断上一个响应者

  • 如果当前这个view是控制器的view,那么控制器就是上一个响应者
  • 如果当前这个view不是控制器的view,那么父控件就是上一个响应者

四、寻找最合适的view

  • 让一个view不接受触摸事件:
    • userInteractionEnabled = NO
    • hidden = YES
    • alpha = 0.0~0.01
  • 寻找最合适的view:
    • 首先查找当前控件的子控件,从后遍历,看是否是合适的响应者。
      • 通过此方法来判断我们所点击的点是否在当前view上
 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    return NO;
}
    *  之后通过此方法来获取一个最合适的view
  - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    *  探究一下`- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event`的底层实现:
  // 寻找最合适view
  // point:也是方法调用者坐标系上的点
  - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
  {
// 1.判断下自己能否接收触摸事件
      if (self.userInteractionEnabled == NO || self.hidden == YES ||   self.alpha <= 0.01) return nil;
    // 2.判断下点在不在当前控件上
    // 用pointInside方法判断点在不在控件上,point这个必须是方法调用者坐标系上的点
    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 *childV = self.subviews[i];
        // 把自己坐标系上点转化成子控件坐标系上点
        CGPoint childP = [self convertPoint:point toView:childV];
        UIView *fitView = [childV hitTest:childP withEvent:event];
        // 如果找到最合适view就直接返回
        if (fitView) {
            return fitView;
        }
    }
    // 4.自己就是最合适view
    return self;
}

你可能感兴趣的:(iOS - 事件的产生和传递)