CALayer mask change animation with fading effect

I have UIView

, with view.layer.mask

an instance installed CAShapeLayer

. The shape layer contains the path, and now I want to add a hole to this shape by adding a second even / odd rule shape and a fading appearance of that hole.

The problem is that adding to the path doesn't seem to animate:

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

      

How could I bring this to life?

+3


source to share


2 answers


After some nagging, a workaround came up:

  • Create a layer with two underlayers with two desired shapes and use it as a mask
  • Animate the opacity of the first sublayer (no hole) from 1 to 0.


This works because the child instances CAShapeLayer

appear to be used as a union. When you hide the first sublevel without a hole, only the hole will open, the overall 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"];

      

+5


source


You cannot use UIView animations to animate CALayers.

Most layer property changes make animation the default (implicit animation). As far as I remember, layer style path changes are an exception.

You will need to create a CAAnimation object where the property you are animating is the path on your mask layer.

However, this probably won't give the effect you want. This is because when the path changes on a shape layer, Core Animation tries to animate the path shape change. In addition, path changes only work correctly when the starting and ending paths have the same number and type of control points.



I'm not sure how you will achieve crossfading between two different masks without a lot of work.

Off the top of my head, the only way I can do this is to create a snapshot of a new view with a modified mask (perhaps using Core Image filters) and then crossfade the layer that displays that snapshot. Once the crossfade is complete, you will set the new path to your mask layer with no animation, and then remove the snapshot bitmap showing the real view below.

There might be an easier way to achieve what you need, but I don't know what that would be. Maybe one of the CA experts who contributes to SO could call back here.

+1


source







All Articles