Animations
With a firm grasp of what a layer is and how it applies to the view hierarchy, let's move on to the animation part of Core Animation. There are two types of animations—explicit animation and implicit animation. While both types of animation accomplish the same goal—animating your interface—they are approached quite differently. Implicit animations are easier to code, so we will go over those first.
Implicit Animations
One of the beautiful parts of Core Animation is that you do not have to actually write any animation code for most of the basic animations that you would want to use. For example, if you want your newly created view to fade into view as opposed to just appearing, the following code would produce that effect:
[[myView animator] setHidden:NO];
With that one line of code, your view will slowly fade into view using the default animation duration. If you wanted the view to slide up from the bottom of the window while it is fading into place, the following would produce that:
NSRect frame = [myView frame]; //While it is hidden move it to the start position frame.origin.y -= frame.size.height; [myView setFrame:frame]; //Now animate the moving and the opacity frame.origin.y += frame.size.height; [[myView animator] setFrame:frame]; [[myView animator] setHidden:NO];
Notice that the only difference between these message calls and the normal messages to move or display a view is the [myView animator] portion of the call. What this change does is route your message to an animator proxy object instead of sending the message directly to the view. The animator proxy object will accept any message call that would be appropriate to send to the view itself and can be animated. When the message is sent to the animator, the property will be changed using animation just as if you had used explicit animation (as discussed next) with only one noticeable difference.
Explicit Animations
Explicit animation is quite a bit more complex than implicit animation. Unlike implicit animation, explicit animation requires you to build the animation objects, set their properties, and then apply those animation objects to the object you wish animated. For example, to perform the same fade-in effect shown previously using explicit animation, the following code is required:
CABasicAnimation *animation = [CABasicAnimation animation]; [animation setToValue:[NSNumber numberWithBool:NO]];
If you run this piece of example code, you will notice an odd effect. When the code fires, the view will appear momentarily and then disappear again. Did something go wrong? What actually happened was a byproduct of explicit animations and is the one very noticeable difference between implicit animations and explicit animations. When you invoke an explicit animation, the property that you animated will reset to its original value by default, whereas an implicit animation will remain in the end state. To make the property change permanent requires a bit more code:
CABasicAnimation *animation = [CABasicAnimation animation]; [animation setRemovedOnCompletion:NO]; [animation setFillMode:kCAFillModeForwards];
This tells Core Animation to not remove the animation when it has completed and that the receiver is to remain visible in its final state. Unfortunately, this is not the end of it. At this point, when the animation has completed the animation is still "running" against the layer. If you attempt to reverse the animation by adding another animation on the property, the view will again flicker. The final step to make the change permanent is to add a delegate to the animation which will set the property to the final value and remove the animation:
[animation setDelegate:self];
And add the following method to the delegate (note that I used the controller as the delegate for brevity):
- (void)animationDidStop:(CABasicAnimation *)theAnimation finished:(BOOL)flag { CALayer *layer = [testView layer]; NSString *path = [theAnimation keyPath]; [layer setValue:[theAnimation toValue] forKeyPath:path]; [layer removeAnimationForKey:path]; }