There are two very different issues at play here:
If you change one of your layer's animatable properties (i.e. not with a
CABasicAnimation
, but rather changing the layer's properties in code, directly) Core Animation may apply implicit animations to the layer (a relatively fast animation, but an animation nonetheless). For example, if you changemyLayer.opacity
, Core Animation may automatically apply implicit animations to fade this effect. Likewise if you directly changemyLayer.strokeEnd
, it may animate the change of the stroke end (you'll see it quickly drawing the line, rather than just immediately appearing).By using
[CATransaction setDisableActions:YES]
, you can instruct Core Animation to not perform these implicit animations that may apply when you change the layer's properties directly. By using[CATransaction setDisableActions:NO]
, you will re-enable the implicit animations.When you create a
CABasicAnimation
, there arefromValue
,toValue
, andbyValue
properties (which according to the documentation, "All are optional, and no more than two should be non-nil
."). Frequently you'll see animations that specify both thefromValue
andtoValue
. But you want, you can specify one, and Core Animation will determine what the others should be.For example, let's assume you just created a
CAShapeLayer
(and by default,strokeEnd
is1.0
). Then if I want to animatestrokeEnd
from 0 to 100%, you can just use:CABasicAnimation *stroke = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; stroke.fromValue = @(0.0); stroke.duration = 1.0f; [myLayer addAnimation:stroke forKey:nil];
Note, I did not have to specify the
toValue
of@(1.0)
, because it will automatically default to the current value ofmyLayer.strokeEnd
(which happens to be 1.0 in this example).
Where these two disparate aspects of Core Animation interact is when you're writing an animation using CABasicAnimation
in which you not only want to specify the animation, but you also want to alter the properties of the layer, directly, right before the animation commences.
For example, if I added a CAShapeLayer
as a sublayer
, but wanted to animate the drawing of the first half of it (i.e. animate strokeEnd
from 0.0
to 0.5
), you might theoretically want to (a) specify myLayer.shapeEnd
to be the final value (e.g. 0.5
); and (b) create a CABasicAnimation
with a fromValue
of @(0.0)
(but you could omit toValue
because we've already set the layer's shapeEnd
to the appropriate value). But, going back to point 1 at the start of my answer, when we set a layer property directly, such as myLayer.shapeEnd
, you might want to setDisableActions
to YES
, so there's no attempt at any implicit animation (given that we're about to specify the actual desired animation with the CABasicAnimation
).
// set the layer's strokeEnd directly (with no implicit animation)
[CATransaction setDisableActions:YES];
myLayer.strokeEnd = 0.5;
[CATransaction setDisableActions:NO];
// now animate the layer's stroke end from 0.0 to the final value,
// which, because we didn't specify `toValue`, will default to the
// current value of `myLayer.strokeEnd` (which we happened to set
// right above)
CABasicAnimation *stroke = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
stroke.fromValue = @0.0;
stroke.duration = 1.0f;
[myLayer addAnimation:stroke forKey:nil];
In practice, I find the setDisableActions
is often unnecessary, but technically, if you're setting the layer's properties and you want to ensure that there's no implicit animation initiated, you may wish to use setDisableActions
, as shown above.
But, as you might infer from this discussion, the fact that we do not need to set toValue
is not a direct result of using CATransaction
or its method setDisableActions
. The toValue
is not needed in this example because we set the layer's strokeEnd
before starting the animation. We just happen to use CATransaction setDisableActions
to ensure there's no implicit animation initiated when changing layer properties directly.