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

iOS带曲线视图的点击事件冲突问题:曲线区域点击识别

解决CurveView遮罩区域点击穿透问题

这个问题的核心原因很明确:CAShapeLayer的mask仅负责视觉上裁剪视图,不会改变视图的点击响应边界。你的CurveView虽然通过mask实现了底部曲线的视觉效果,但它的可点击范围还是完整的矩形frame,所以黄色视图被绿色视图覆盖的区域(红色高亮区),点击时依然会触发绿色视图的tap手势。

要解决这个问题,最精准的方式是重写CurveView的hitTest(_:with:)方法,让视图只响应mask路径范围内的点击,超出路径的点击则穿透到下方视图。

修改CurveView类,添加点击区域判断

class CurveView: UIView {
    // 保存mask的路径,避免每次hitTest都重新创建
    private var maskPath: CGPath?
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.createBottomCurve()
    }
    
    private func createBottomCurve() {
        let offset: CGFloat = self.frame.width / 1.2
        let bounds: CGRect = self.bounds
        let rectBounds: CGRect = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width, height: bounds.size.height / 2)
        let rectPath: UIBezierPath = UIBezierPath(rect: rectBounds)
        let ovalBounds: CGRect = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width: bounds.size.width + offset, height: bounds.size.height)
        let ovalPath: UIBezierPath = UIBezierPath(ovalIn: ovalBounds)
        rectPath.append(ovalPath)
        
        let maskLayer: CAShapeLayer = CAShapeLayer()
        maskLayer.frame = bounds
        maskLayer.path = rectPath.cgPath
        self.layer.mask = maskLayer
        
        // 保存mask的路径,供hitTest使用
        maskPath = rectPath.cgPath
    }
    
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        guard let path = maskPath else {
            return super.hitTest(point, with: event)
        }
        
        // 判断点击点是否在mask路径范围内
        if path.contains(point) {
            return super.hitTest(point, with: event)
        } else {
            // 不在范围内,返回nil,点击事件会穿透到下方视图
            return nil
        }
    }
}

代码说明

  1. 新增maskPath属性保存遮罩路径,避免每次hitTest重复生成路径,提升性能;
  2. 重写hitTest(_:with:)方法:
    • 先校验点击点是否在maskPath的范围内;
    • 若在范围内则正常响应点击,若不在则返回nil,系统会自动向下查找可响应的视图(也就是你的黄色视图)。

其他可选方案

如果CurveView的曲线区域完全不需要交互,也可以通过调整视图层级或直接裁剪视图的方式解决,但上面的hitTest方案是最灵活且精准的——它完全匹配你视觉上的可交互区域。

内容的提问来源于stack exchange,提问作者Francis F

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 22:37:27