You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让上层UIView响应点击手势后将手势传递给下层UIView?

如何让上层UIView响应点击手势后将手势传递给下层UIView?

看起来你遇到了重叠视图之间手势事件传递的坑!我先帮你拆解下当前代码的问题,再给你可行的解决方案~

问题出在哪?

你设置了cancelsTouchesInView = NO,但这个属性的作用是阻止手势识别器拦截当前视图自身的原生触摸事件(比如touchesBegan:),而不是让触摸事件“穿透”到下层视图。

现在你的视图层级是:self.view → 先添加custom_overlay_2,再添加custom_overlay_1,所以custom_overlay_1在最上层。当你点击重叠区域时,触摸事件只会被最上层的custom_overlay_1接收,下层的custom_overlay_2根本拿不到触摸事件,自然它的手势识别器不会触发。

给你两个可行的解决思路:

思路1:手动在手势处理方法中触发下层视图的手势逻辑

既然上层视图能拿到触摸事件,我们可以在handle_tap_1里,主动检查点击位置是否也在custom_overlay_2的范围内,如果是,就调用handle_tap_2的逻辑。

修改你的手势处理方法:

- (int)handle_tap_1 : (UITapGestureRecognizer *)gesture {
    NSLog(@" *** *** handle_tap_1 !!!");
    if (gesture.state == UIGestureRecognizerStateRecognized) {
        NSLog(@" *** *** recognized tap detected in handle_tap_1 !!!");
        
        // 转换点击坐标到custom_overlay_2的坐标系
        CGPoint tapPoint = [gesture locationInView:custom_overlay_2];
        // 判断点击点是否在custom_overlay_2的范围内
        if (CGRectContainsPoint(custom_overlay_2.bounds, tapPoint)) {
            // 手动触发handle_tap_2的逻辑
            [self handle_tap_2:custom_overlay_2.gestureRecognizers.firstObject];
        }
    }
    return 0;
}

- (int)handle_tap_2 : (UITapGestureRecognizer *)gesture {
    NSLog(@" *** *** handle_tap_2 !!!");
    if (gesture.state == UIGestureRecognizerStateRecognized) {
        NSLog(@" *** *** recognized tap detected in handle_tap_2 !!!");
    }
    return 0;
}

思路2:将两个手势都添加到父视图,通过点击区域判断响应

把两个手势识别器都加到self.view上,然后在处理方法里判断点击位置属于哪个overlay视图,这样就不用依赖视图层级的遮挡问题:

// 初始化部分修改
UIView *custom_overlay_1 = [[UIView alloc] initWithFrame:given_frame];
UIView *custom_overlay_2 = [[UIView alloc] initWithFrame:given_frame];
// 注意:overlay不需要添加手势,手势加在父视图上
UITapGestureRecognizer *custom_recognizer_1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handle_tap_1:)];
UITapGestureRecognizer *custom_recognizer_2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handle_tap_2:)];
[custom_recognizer_1 setCancelsTouchesInView:NO];
[custom_recognizer_2 setCancelsTouchesInView:NO];
// 把手势加到self.view
[self.view addGestureRecognizer:custom_recognizer_1];
[self.view addGestureRecognizer:custom_recognizer_2];
// 还是添加两个overlay到视图
[self.view addSubview:custom_overlay_2];
[self.view addSubview:custom_overlay_1];

// 处理方法修改
- (int)handle_tap_1 : (UITapGestureRecognizer *)gesture {
    CGPoint tapPoint = [gesture locationInView:self.view];
    // 只有点击在custom_overlay_1范围内才处理
    if (CGRectContainsPoint(custom_overlay_1.frame, tapPoint) && gesture.state == UIGestureRecognizerStateRecognized) {
        NSLog(@" *** *** handle_tap_1 !!!");
        NSLog(@" *** *** recognized tap detected in handle_tap_1 !!!");
    }
    return 0;
}

- (int)handle_tap_2 : (UITapGestureRecognizer *)gesture {
    CGPoint tapPoint = [gesture locationInView:self.view];
    // 只有点击在custom_overlay_2范围内才处理
    if (CGRectContainsPoint(custom_overlay_2.frame, tapPoint) && gesture.state == UIGestureRecognizerStateRecognized) {
        NSLog(@" *** *** handle_tap_2 !!!");
        NSLog(@" *** *** recognized tap detected in handle_tap_2 !!!");
    }
    return 0;
}

额外提示

如果你的custom_overlay_1不需要处理触摸事件,只是用来显示内容,可以设置custom_overlay_1.userInteractionEnabled = NO,这样触摸事件会直接穿透到下层视图。但显然你需要上层视图也响应手势,所以这个方法不适用当前场景。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 13:08:08