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的最底层,这样挖空的区域才能直接显示相机预览; - 如果需要调整圆角矩形的大小(比如不是全屏的圆角框),只需要修改
RoundedRectangle的frame或者在自定义Shape中调整路径的位置即可。
内容的提问来源于stack exchange,提问作者Will




