英文:
How to combine / nest CALayer masks?
问题
以下是翻译好的部分:
"Is it possible use nested CALayer
mask to create one combined mask? My goal is to create a complex shapes by combining / masking other complex shapes and applying a gradient to the result.
是否可以使用嵌套的CALayer
蒙版来创建一个组合蒙版?我的目标是通过组合/蒙版其他复杂形状并将渐变应用于结果来创建复杂的形状。
For example one CAShapeLayer
my hold a path which draws a unicorn head and a second CAShapeLayer
my hold a path which draws a flower. By applying the flower layer as mask to the unicorn layer, I get a "flowerly unicorn". In then next step I could than apply this complex shape to a CAGradientLayer
to get a "flowerly unicorn rainbow".
例如,一个CAShapeLayer
可以包含绘制独角兽头部的路径,第二个CAShapeLayer
可以包含绘制花朵的路径。通过将花朵图层用作独角兽图层的蒙版,我可以得到一个"花朵独角兽"。然后,在下一步中,我可以将这个复杂形状应用到CAGradientLayer
上,以获得一个"花朵独角兽彩虹"。
However, when applying the unicorn layer (with the flower mask) as mask for the gradient, the result is a unicorn rainbow. The flower mask already applied to the unicorn is skipped.
然而,当将独角兽图层(带有花朵蒙版)用作渐变的蒙版时,结果是一个独角兽彩虹。已经应用到独角兽的花朵蒙版被跳过。
Is there any other way to combine / nest layer mask to create such shapes?
是否有其他方法来组合/嵌套图层蒙版以创建这样的形状?
The following code illustrates the problem using some simpler shapes:
以下的代码示例使用一些简单的形状来说明问题:
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
Now I would assume to get a half circle shape with a gradient. However, I get a circle with a gradient instead. It seem that when applying the circleLayer
as mask to the gradientLayer
the rect mask is not considered / applied...
现在我会认为会得到一个带有渐变的半圆形状。然而,我得到的却是一个带有渐变的圆形。似乎在将circleLayer
用作gradientLayer
的蒙版时,矩形蒙版没有被考虑/应用...
Am I doing something wrong? Is there another way to solve this? Masking and combining masks is quite a common task in many different applications. Thus I wonder if such a powerful framework as CA has a way of doing this.
我是否做错了什么?是否有其他解决方法?在许多不同的应用中,蒙版和组合蒙版是相当常见的任务。因此,我想知道像CA这样强大的框架是否有一种方法来实现这一点。"
英文:
Is it possible use nested CALayer
mask to create one combined mask? My goal is to create a complex shapes by combining / masking other complex shapes and applying a gradient to the result.
For example one CAShapeLayer
my hold a path which draws a unicorn head and a second CAShapeLayer
my hold a path which draws a flower. By applying the flower layer as mask to the unicorn layer, I get a "flowerly unicorn". In then next step I could than apply this complex shape to a CAGradientLayer
to get a "flowerly unicorn rainbow".
However, when applying the unicorn layer (with the flower mask) as mask for the gradient, the result is a unicorn rainbow. The flower mask already applied to the unicorn is skipped.
Is there any other way to combine / nest layer mask to create such shapes?
<hr>
The following code illustrates the problem using some simpler shapes:
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
Now I would assume to get a half circle shape with a gradient. However, I get a circle with a gradient instead. It seem that when applying the circleLayer
as mask to the gradientLayer
the rect mask is not considered / applied...
Am I doing something wrong? Is there another way to solve this? Masking and combining masks is quite a common task in many different applications. Thus I wonder if such a powerful framework as CA has a way of doing this.
答案1
得分: 2
如@DuncanC指出,蒙版不能嵌套。因此,将Layer A应用为Layer B的蒙版,然后将Layer B应用为Layer C的蒙版并不起作用如预期。这只会使用B的原始内容作为蒙版,并不考虑Layer A所做的更改。
我通过首先“展平”Layer B + Mask Layer A的结果来绕过这个限制。通过创建此结果的图像,然后将其应用为Layer C的蒙版来实现:
let layerA = CAShapeLayer() // ... 添加一些形状
let layerB = CAShapeLayer() // ... 添加一些形状
// 将A应用为B的蒙版
layerB.mask = layerA
// 展平B
let flatB = layerB.flatten()
// 将flatB应用为C的蒙版
let layerC = CAShapeLayer() // ... 添加一些形状
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
}
}
这可能不是完美的解决方案,但在我的情况下效果很好。也许这对其他人也有帮助。
英文:
As @DuncanC pointed out mask cannot be nested. So, applying Layer A as mask to Layer B and than applying Layer B as mask to Layer C does not work as expected. This will only use the original content of B as mask and not taking account the changed made by Layer A.
I was able to get around this limitation by first "flattening" the result of Layer B + Mask Layer A. This is done by creating an image of this result and than applying this as mask to Layer 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
The flattening is done using this CALayer extension:
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
}
}
This might not be the perfect solution but it works very well in my case. Maybe this might help others as well.
答案2
得分: 0
无法嵌套遮罩。您需要为要隐藏的每个图层创建一个唯一的遮罩。
英文:
Answer: You can't nest masks. You will need ot create a unique mask for each layer that masks the parts of that layer that you want to hide.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论