如何使用Material样式在Canvas中填充Path并实现半透明效果
使用GraphicsContext为Path填充Material样式实现半透明效果
Canvas的闭包参数包含GraphicsContext,可用于绘制和填充图形。但直接用Material样式填充Path时,会得到近乎纯黑色的填充,而非预期的半透明模糊效果:
struct ContentView: View { let loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." var body: some View { ZStack { HStack(spacing: 0) { Color.clear Color.orange } Text(loremIpsum) .font(.title2) .padding() RoundedRectangle(cornerRadius: 10) .fill(.ultraThinMaterial) .frame(width: 200, height: 100) .padding(.bottom, 160) Canvas { ctx, size in let path = Path( roundedRect: CGRect( x: (size.width - 200) / 2, y: (size.height - 100) / 2 , width: 200, height: 100 ), cornerRadius: 10 ) ctx.fill(path, with: .style(.ultraThinMaterial)) } .padding(.top, 160) } } }

尝试使用.palette组合样式时,Material的模糊效果会被完全忽略:
ctx.fill(path, with: .palette([ .color(white: 0, opacity: 0.2), .style(.ultraThinMaterial) ]))

解决方案
要在GraphicsContext中为Path实现正确的Material半透明模糊效果,需要先将目标路径设置为裁剪区域,再绘制覆盖整个Canvas范围的Material背景。这样裁剪后,只有路径内的Material会被保留,效果与常规View填充Material一致:
Canvas { ctx, size in let path = Path( roundedRect: CGRect( x: (size.width - 200) / 2, y: (size.height - 100) / 2 , width: 200, height: 100 ), cornerRadius: 10 ) // 将路径设置为裁剪区域 ctx.clip(to: path) // 绘制覆盖整个Canvas的Material,裁剪后仅保留路径内的部分 ctx.fill(Path(CGRect(origin: .zero, size: size)), with: .style(.ultraThinMaterial)) } .padding(.top, 160)
原理是:Material样式的模糊效果需要基于其背后的内容计算,直接填充路径时,GraphicsContext无法正确识别路径外的背景内容来生成模糊;而先裁剪再绘制全屏Material,能让系统正确计算模糊效果,最终呈现出预期的半透明毛玻璃效果。
内容的提问来源于stack exchange,提问作者Benzy Neez
相关产品推荐
相关产品推荐

