iOS hitTest方法找到合适的View底层实现

什么时候调用:当事件传递给当前View时, 会调用当前Veiw的hitTest方法;
作用:寻找最适合的View.
返回值:返回谁,谁就是最适合的view,谁就响应事件,就会调用谁的touches方法

在上一篇提到事件传递过程中如何找到最合适的View来处理触摸事件,分为四步:

1.判断自己能否接收事件
2.点在不在自己身上
3.从后往前遍历自己了的子控件,把事件传递给子控件,调用子控件的hitTest,
4.如果子控件没有找到最适合的View,那么自己就是最适合的View.

如果需要重写hitTest方法,这4个步骤是必须的:

- (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]) {
        return nil;
    }
    
    //3.从后往前遍历自己的子控件,把事件传递给子控件,调用子控件的hitTest,
    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) {
            return fitView;
        }
        
    }
    //4.如果子控件没有找到最适合的View,那么自己就是最适合的View.
    return self;
    
}

其中判断点在不在自己身上,系统提供了一个pointInside:方法,会在hitTest内部调用该方法。

注意:必须得要跟方法调用者在同一个坐标系

可以看到在上面hitTest内部实现代码中, 有一个转换坐标系的操作,就是为了点和方法调用这在同一个坐标系中。

        //把当前点的坐标系转换成子控件的坐标系
        CGPoint childP = [self convertPoint:point toView:childView];
        
        UIView *fitView = [childView hitTest:childP withEvent:event];

hitTest的应用

怎么办到点击黄色view和Button重叠部分让Button响应点击?


分析:hitTest方法的作用就是找到最合适的View来响应点击事件,如果按正常流程走的话,点击重叠部分,肯定是黄色View来响应该点击事件,只需要重写黄色View的hitTest方法,判断如果点击在重叠部分,就返回红色Button即可。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    
    //判断点在不在红色按钮身上, 如果在,直接返回红色按钮
    CGPoint redP = [self convertPoint:point toView:self.redBtn];
    if ([self.redBtn pointInside:redP withEvent:event]) {
        return self.redBtn;
    }
    //否则保持原有做法.
    return [super hitTest:point withEvent:event];
    
}

你可能感兴趣的:(iOS hitTest方法找到合适的View底层实现)