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

SwiftUI如何使用inverted mask实现半透明遮罩镂空高亮效果

问题原因

  • 你的HoleShapeMask仅定义了需要镂空的高亮区域路径,没有先绘制全屏尺寸的底层路径,导致eoFill奇偶填充规则无法生效(该规则需要至少两层重叠路径才能计算镂空区域)
  • 遮罩层的frame布局优先级设置不当,没有优先撑满整个父容器
  • 高亮区域坐标仅在onAppear时获取一次,后续视图布局变化(如横竖屏切换)时坐标不会同步更新

修复后可运行代码

// 调整镂空遮罩路径,先绘制全屏背景,再叠加需要挖空的高亮区域
func HoleShapeMask(in holeRect: CGRect, viewBounds: CGRect) -> Path {
    return Path { path in
        // 先添加全屏尺寸的路径
        path.addRect(viewBounds)
        // 再添加需要镂空的高亮区域路径
        path.addRect(holeRect)
    }
}

struct ContentView: View {
    @State private var highlightRect: CGRect = .zero
    @State private var viewBounds: CGRect = .zero

    var body: some View {
        GeometryReader { fullGeom in
            ZStack {
                // 此处替换为你的实际页面内容,示例用红色背景模拟完整页面
                Color.red
                    .ignoresSafeArea()
                
                Text("需要高亮的内容")
                    .foregroundColor(.blue)
                    .frame(width: 124, height: 100)
                    .background(Color.white)
                    .overlay(
                        GeometryReader { itemGeom in
                            Color.clear
                                .onAppear {
                                    highlightRect = itemGeom.frame(in: .global)
                                }
                                // 适配布局变化时同步更新高亮区域坐标
                                .onChange(of: itemGeom.frame(in: .global)) { newRect in
                                    highlightRect = newRect
                                }
                        }
                    )
            }
            .onAppear {
                viewBounds = fullGeom.frame(in: .global)
            }
            .onChange(of: fullGeom.frame(in: .global)) { newBounds in
                viewBounds = newBounds
            }
            // 叠加半透明黑色遮罩
            .overlay(
                Color.black.opacity(0.8)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .ignoresSafeArea()
                    // 用eoFill规则镂空高亮区域
                    .mask(
                        HoleShapeMask(in: highlightRect, viewBounds: viewBounds)
                            .fill(style: FillStyle(eoFill: true))
                    )
            )
        }
    }
}

关键修改说明

  • 调整HoleShapeMask逻辑,同时传入全屏尺寸和高亮区域尺寸,先绘制全屏路径再叠加高亮路径,确保奇偶填充规则可以正确计算出镂空区域
  • 新增viewBounds变量存储全屏尺寸,适配横竖屏切换等布局变化场景
  • 新增onChange监听坐标变化,确保高亮区域坐标和全屏尺寸实时更新
  • 遮罩层添加ignoresSafeArea,保证可以覆盖到状态栏、底部安全区等系统区域,实现全屏遮罩效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 18:24:01