提问人:Andrei Herford 提问时间:3/7/2023 最后编辑:Andrei Herford 更新时间:3/8/2023 访问量:170
如何组合/嵌套 CALayer 面具?
How to combine / nest CALayer masks?
问:
是否可以使用嵌套蒙版创建一个组合蒙版?我的目标是通过组合/遮罩其他复杂形状并对结果应用渐变来创建复杂的形状。CALayer
例如,一个我拿着一条画独角兽头的路径,第二个我拿着一条画一朵花的路径。通过将花层作为面具贴在独角兽层上,我得到了一只“花独角兽”。在下一步中,我可以将这种复杂的形状应用于“花独角兽彩虹”。CAShapeLayer
CAShapeLayer
CAGradientLayer
但是,当应用独角兽层(带有花朵蒙版)作为渐变的蒙版时,结果是独角兽彩虹。已经涂在独角兽身上的花面具被跳过了。
有没有其他方法可以组合/嵌套图层蒙版来创建这样的形状?
下面的代码使用一些更简单的形状来说明该问题:
let rectLayer = CAShapeLayer()
rectLayer = // ... a simple rect shape
let circleLayer = CAShapeLayer()
circleLayer = // ... a circle shape, half overlapping the rect
// Apply rect as mask to create half circle
circleLayer.mask = rectLayer
// Some gradient
let gradientLayer = CAGradientLayer()
gradientLayer = // ... set up gradient with some colors
// Apply masked circle as mask to get a half circle with gradient
gradientLayer.mask = circleLayer
现在我假设得到一个带有渐变的半圆形状。但是,我得到了一个带有渐变的圆圈。似乎在将 as 蒙版应用于矩形蒙版时不考虑/应用......circleLayer
gradientLayer
我做错了什么吗?有没有其他方法可以解决这个问题?在许多不同的应用中,遮罩和组合面罩是一项非常常见的任务。因此,我想知道像 CA 这样强大的框架是否有办法做到这一点。
答:
答:你不能嵌套掩码。您将需要为每个图层创建一个唯一的蒙版,以蒙蔽要隐藏的该图层的部分。
评论
正如@DuncanC所指出的,掩码不能嵌套。因此,将 A 层作为掩码应用于层 B,而不是将 B 层作为掩码应用于层 C 并不能按预期工作。这将仅使用 B 的原始内容作为掩码,而不考虑 A 层所做的更改。
我能够通过首先“展平”图层 B + 遮罩图层 A 的结果来绕过这个限制。这是通过创建此结果的图像并将其作为掩码应用于图层 C 来完成的:
let layerA = CAShapeLayer() // ... add some shapes
let layerB = CAShapeLayer() // ... add some shapes
// Apply A as mask to B
layerB.mask = layerA
// Flatten B
let flatB = layerB.flatten()
// Apply flatB as mask to C
let layerC = CAShapeLayer() // ... add some shapes
layerC.mask = flatB
扁平化是使用此 CALayer 扩展完成的:
extension CALayer {
func flatten() -> CALayer {
guard let colorSpace = CGColorSpace(name: CGColorSpace.sRGB),
let ctx = CGContext(data: nil, width: Int(bounds.width), height: Int(bounds.height), bitsPerComponent: 8, bytesPerRow: 4*Int(bounds.width), space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return CALayer() }
ctx.translateBy(x: 0, y: bounds.height)
ctx.scaleBy(x: 1.0, y: -1.0)
render(in: ctx)
let image = ctx.makeImage()
let flattenedLayer = CALayer()
flattenedLayer.frame = frame
flattenedLayer.contents = image
return flattenedLayer
}
}
这可能不是完美的解决方案,但在我的情况下效果很好。也许这也可能对其他人有所帮助。
评论