In the course of creating slides for my upcoming Animation in iOS talk, I’ve been re-running through relevant WWDC talks (and docs, and sample code, and Nathan Eror’s awesome CA360 project, anything I can get my hands on about CoreAnimation).

I came across a handy illustrative example of how to fade a layer in using an explicit CoreAnimation animation from the “Building Animation Driven Interfaces” talk. In practice, you wouldn’t really do this–it’s much easier to just use UIKit animations. But, it helps as a teaching exercise, so I wanted to include it in the sample code I plan to release for my talk.

CABasicAnimation *myAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];

myAnimation.toValue = [NSNumber numberWithFloat:1.0];
myAnimation.duration = 2.0;
myAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

[myUIImageView.layer addAnimation:myAnimation forKey:@"myAnimation"];

This animation ran fine, with one wrinkle. CoreAnimation’s explicit animations do not change the underlying model object. They animate any changes in the presentation layer, but the underlying model is unchanged. Which means, when you are done with the animation, the model’s value is still the same. For the above code, that meant the nice fade-in of a UIImageView I just created disappeared (POOF!) as soon as the animation was done; the UIImageView’s layer still had an opacity of 0.0.

To fix this, the WWDC presenters direct us to add one line:

[myUIImageView.layer setOpacity:1];

This also changes the underlying model object. Great! EXCEPT. This also didn’t work for me. Now, I was getting some wonky, erratic behavior, and my nice 2 second animation seemed to happen in an instance. Sometimes I’d get a slow fade, sometimes, it’d just change. Luckily, another WWDC 10 talk, “Core Animation in Practice: Part 1″ showed me the way through.

You can sometimes get away with just specifying the animation’s toValue, since the fromValue is just taken to be the current value of the model object. But! Since I was now modifying the model object, the toValue and the model value were the same! Hence–nothing to animate.

Adding just one line that specifies a fromValue made everything run as expected–a nice, 2 second animated fade in, with no disappearing layer once the animation was done:

CABasicAnimation *myAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];

// setting the opacity here ensures the layer doesn't disappear after the animation is over
[myUIImageView.layer setOpacity:1];

// when changing the model value, you must use BOTH a fromValue and a toValue
myAnimation.fromValue = [NSNumber numberWithFloat:0.0];
myAnimation.toValue = [NSNumber numberWithFloat:1.0];
myAnimation.duration = 2.0;
myAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

[myUIImageView.layer addAnimation:myAnimation forKey:@"myAnimation"];



2 Responses to “Making CoreAnimation’s explicit animations stick”  

  1. 1 Bertilholmberg

    Thanks, this saved my day!

  2. 2 Neilio

    Boom! Solved.

Leave a Reply