事件响应机制

事件分发机制

当屏幕上有事件发生时,事件会自上而下,去检查,谁来响应。

  • 前面几个基佬是系统层级的响应,顺序是

UIApplication - > UIWindow - > ...

这种响应规则就是传说中的hitTest,通过这个名字就看出来个大概,实现则是:


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    if (self.alpha <= 0.01 || !self.userInteractionEnabled || self.hidden) {
    
        return nil;
        
    }
    
    BOOL inside = [self pointInside:point withEvent:event];
    
    UIView *hitView = nil;
    
    if (inside) {
    
        NSEnumerator *enumerator = [self.subviews reverseObjectEnumerator];
        
        for (UIView *subview in enumerator) {
        
            hitView = [subview hitTest:point withEvent:event];
            
            if (hitView) {
            
                break;
            
            }
    
        }
    
        if (!hitView) {
            hitView = self;
        }
        return hitView;
    } 
    else {
        return nil;
    }
}


据说内部是这样实现的,看到它大概就是先判断当前的状态是否适合有事件产生。然后就是通过pointinside来判断点击的点是否在自己的frame内。如果满足就去遍历他里面的所有subView,如果没有合适的subview来响应,就只有自己来了。这大概就是事件产生时寻找它响应的view的过程。

注意几点:

1、默认的hit-testing顺序是按照UIView中Subviews的逆顺序

2、如果View的同级别Subview中有重叠的部分,则优先检查顶部的Subview,如果顶部的Subview返回nil, 再检查底部的Subview

3、Hit-Test也是比较聪明的,检测过程中有这么一点,就是说如果点击没有发生在某View中,那么该事件就不可能发生在View的Subview中,所以检测过程中发现该事件不在ViewB内,也直接就不会检测在不在ViewF内。也就是说,如果你的Subview设置了clipsToBounds=NO,实际显示区域可能超出了superView的frame,你点击超出的部分,是不会处理你的事件的,就是这么任性!

响应者链Responder Chain

找到这个view后,就会涉及到会找到这个view上的UIResponder,这个东西进去看就知道是一堆事件的集合。
然后它会根据传递链,来自下而上的寻找谁能处理这个事件。谁能处理,就在这结束,不往上寻找。

响应链条的响应顺序是view->superview(or vc)->superview(or vc)->window->UIApplication,ps如果中间遇到vc的,就绕下vc,在向上。到头没了就废弃,不处理。

总结,ios的触摸事件是2个顺序:

  1. 是自上而下以hitTest的机制寻找响应的view.
  2. 是找到之后又自下而上的寻找响应事件。

你可能感兴趣的:(事件响应机制)