You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SwiftUI中能否反转clipShape实现形状镂空?如何裁剪蓝色矩形露出下层相机预览层

实现蓝色矩形的反向裁剪(露出相机预览的圆角区域)

你的需求核心是反转clipShape的作用:默认clipShape是保留裁剪范围内的视图,而你需要保留裁剪范围外的蓝色区域,挖空中间的圆角矩形来露出下方的相机预览。下面是几种可行的解决方案:

方法1:使用inverted()(iOS 16+ 最简洁)

从iOS 16开始,SwiftUI的Shape支持inverted()方法,可以直接反转形状的区域。你只需要给RoundedRectangle加上这个修饰符,就能实现反向裁剪:

struct CameraView: View {
    var body: some View {
        ZStack {
            // 相机预览放在最底层,这样被挖空的区域能直接显示它
            CameraPreviewLayer()
            // 蓝色矩形反转裁剪,保留圆角矩形以外的区域
            Rectangle()
                .ignoresSafeArea(.all)
                .foregroundColor(.blue)
                .clipShape(RoundedRectangle(cornerRadius: 20).inverted())
            ShutterButton()
        }
    }
}

这个方法最直观,代码量最少,但只支持iOS 16及以上系统。

方法2:使用mask(兼容iOS 13+)

如果需要兼容更低版本的iOS,可以用mask实现反向裁剪。原理是:mask会保留视图中与遮罩不透明区域重叠的部分,所以我们可以创建一个“全屏挖空圆角矩形”的遮罩,应用到蓝色矩形上:

struct CameraView: View {
    var body: some View {
        ZStack {
            CameraPreviewLayer()
            Rectangle()
                .ignoresSafeArea(.all)
                .foregroundColor(.blue)
                .mask(
                    // 创建全屏矩形,然后用混合模式挖空中间的圆角矩形
                    Rectangle()
                        .overlay(
                            RoundedRectangle(cornerRadius: 20)
                                .fill(Color.black)
                                .blendMode(.destinationOut)
                        )
                        .clipped() // 确保遮罩只在全屏范围内生效
                )
            ShutterButton()
        }
    }
}

这里的blendMode(.destinationOut)会把底层矩形中与圆角矩形重叠的区域完全透明化,最终的遮罩就是“全屏除了中间圆角矩形”的形状,应用到蓝色矩形后就会挖空中间区域。

方法3:自定义反转Shape(兼容iOS 13+)

你也可以自定义一个Shape,直接绘制“全屏减去圆角矩形”的路径,然后用这个Shape作为clipShape的参数:

// 自定义反转圆角矩形Shape
struct InvertedRoundedRectangle: Shape {
    let cornerRadius: CGFloat
    
    func path(in rect: CGRect) -> Path {
        // 绘制全屏矩形路径
        let fullScreenPath = Rectangle().path(in: rect)
        // 绘制圆角矩形路径
        let roundedRectPath = RoundedRectangle(cornerRadius: cornerRadius).path(in: rect)
        // 返回全屏路径减去圆角矩形路径的结果
        return fullScreenPath.subtracting(roundedRectPath)
    }
}

// 在CameraView中使用
struct CameraView: View {
    var body: some View {
        ZStack {
            CameraPreviewLayer()
            Rectangle()
                .ignoresSafeArea(.all)
                .foregroundColor(.blue)
                .clipShape(InvertedRoundedRectangle(cornerRadius: 20))
            ShutterButton()
        }
    }
}

这种方法的好处是自定义Shape可以重复使用,适合多个地方需要相同反向裁剪效果的场景。

注意事项

  • 记得把CameraPreviewLayer放在ZStack的最底层,这样挖空的区域才能直接显示相机预览;
  • 如果需要调整圆角矩形的大小(比如不是全屏的圆角框),只需要修改RoundedRectangleframe或者在自定义Shape中调整路径的位置即可。

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

火山引擎 最新活动