简体   繁体   English

使用淡入淡出效果动画CALayer蒙版更改

[英]Animate CALayer mask change with fade effect

I have a UIView , with view.layer.mask set to an instance of CAShapeLayer . 我有一个UIView ,与view.layer.mask设置的实例CAShapeLayer The shape layer contains a path, and now I want to add a hole to this shape by adding a second shape with even/odd rule, and fade-in the appearance of this hole. 形状图层包含一个路径,现在我想通过添加具有偶数/奇数规则的第二个形状为此形状添加一个孔,并淡入此孔的外观。

The problem is that adding to path doesn't seem to be animatable: 问题是添加到路径似乎不是可动画的:

[UIView animateWithDuration:2 animations:^() {
    CGPathAddPath(parentPath, nil, holePath);
    [v.layer.mask didChangeValueForKey:@"path"];
}];

How would I animate this? 我该如何设置动画?

After some fiddling, found a workaround: 经过一番摆弄,找到了一个解决方法:

  1. Create a layer with two sublayers with two desired shapes, and use it as a mask 创建一个包含两个具有两个所需形状的子图层的图层,并将其用作蒙版
  2. Animate opacity of the first sublayer (without a hole) from 1 to 0. 将第一个子层(没有孔)的不透明度从1设置为0。

This works because child CAShapeLayer instances appear to be used as a union. 这是有效的,因为子CAShapeLayer实例似乎用作联合。 When you hide the first sublayer without a hole, only the hole will be uncovered, the shared area will not change. 隐藏第一个没有孔的子层时,只会打开孔,共享区域不会改变。

CGMutablePathRef p = CGPathCreateMutable();

// First path
CGPathAddPath(p, nil, outerPath);
CAShapeLayer *mask1 = [CAShapeLayer layer];
mask1.path = p;

// 2nd path with a hole
CGPathAddPath(p, nil, innerPath);
CAShapeLayer *mask2 = [CAShapeLayer layer];
mask2.path = p;
mask2.fillRule = kCAFillRuleEvenOdd;

CGPathRelease(p);

// Create actual mask that hosts two submasks
CALayer *mask = [CALayer layer];
[mask addSublayer:mask1];
[mask addSublayer:mask2];
myView.layer.mask = mask;
mask.frame = v.layer.bounds;
mask1.frame = mask.bounds;
mask2.frame = mask.bounds;

// ...

// Hide mask #1
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"opacity"];
a.fromValue = @1.0;
a.toValue = @0.0;
a.duration = 1.0;
a.fillMode = kCAFillModeForwards; // Don't reset back to original state
a.removedOnCompletion = NO;
[mask1 addAnimation:a forKey:@"hideMask1"];

You can't use UIView animation to animate CALayers. 您无法使用UIView动画为CALayers设置动画。

Most layer property changes do animation by default (implicit animation). 大多数图层属性更改默认执行动画(隐式动画)。 As I recall, shape layer path changes are an exception to that. 我记得,形状层路径更改是一个例外。

You'll need to create a CAAnimation object where the property you are animating is the path on your mask layer. 您需要创建一个CAAnimation对象,其中您要设置动画的属性是遮罩层上的路径。

However, that probably won't give the effect you want. 但是,这可能不会产生你想要的效果。 The reason is that when you change a path on a shape layer, Core Animation tries to animate the change in shape of the path. 原因是当您更改形状图层上的路径时,Core Animation会尝试为路径形状的更改设置动画。 Furthermore, path changes only work properly when the starting and ending paths have the same number and type of control points. 此外,当起始路径和结束路径具有相同数量和类型的控制点时,路径更改仅适用。

I'm not sure how you'd achieve a cross-fade between 2 different masks without a lot of work. 我不确定你如何在没有大量工作的情况下实现两种不同面具之间的交叉淡入淡出。

Off the top of my head, the only way I can think of to do this would be to create a snapshot of the new view appearance with the changed mask (probably using Core Image filters) and then do a cross-fade of a layer that displays that snapshot. 在我的脑海中,我能想到的唯一方法是使用更改的蒙版(可能使用Core Image滤镜)创建新视图外观的快照,然后对图层进行交叉渐变。显示该快照。 Once the crossfade is complete, you would install the new path in your mask layer without animation and then remove the snapshot bitmap, revealing the real view underneath. 交叉渐变完成后,您将在没有动画的掩码图层中安装新路径,然后删除快照位图,从而显示下面的真实视图。

There might be a simpler way to achieve what you're after but I don't know what that would be. 可能有一种更简单的方法来实现你所追求的目标,但我不知道那会是什么。 Maybe one of the CA experts that contributes to SO could chime in here. 也许其中一位对SO有贡献的CA专家可能会在这里发表意见。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM