This is another installment in CapTech's ongoing series recapping CocoaConf technical conference for Apple developers held March 21-23 in Northern Virginia. This post focuses on the presentation given by Mark Pospesel on Animation techniques. But before I get into the meat of it, here are a few words about the conference itself. The conference was a treat! Three days of oustanding presentations by accomplished developers, including CapTech's own Jack Cox. The facilities at the Crowne Plaza Dulles were perfectly suited for this kind of event. It seemed like there were interesting people at every table. So the next time CocoaConf heads to your neck of the woods, you should check it out.
Here are a few takeaways I grabbed from his talk.
Mark Pospesal spent 90 minutes guiding participants through the fundamentals and some advanced techniques of animation in Cocoa. Most of the content here would be well-known to developers who have already dug into the API and worked through a comprehensive iOS book or two, like this one by Matt Neuberg. However, Pospesal has provided a great service to the community by developing a animation demo app that lets users explore the elements that go into effective animation. You can download it here. The app takes a simple logo (in this case the CocoaConf logo) and animates it according to a set of adjustable parameters as shown below.
Duration seems pretty straightforward. The animation runs for a period of time, then stops. That's duration. But duration can get plenty tricky when many animations have to run concurrently, or sequentially, or both. When animating on a
UIView, the next animation can be scheduled in the completion block of the first. This can lead to many nested animation blocks that quickly get confusing. When animating
CALayer, animations can be grouped together in a
CAAnimationGroup. In this case the child
CAAnimations inherit all the default values of their parent, so each child's
CAAnimation's begin time can be set relative to the begin time of the parent animation group's begin time.
There is one case where neither completion blocks or animation groups provide much help. This is what I call the jump-start animation scenario. Say you have a sequence of five animations. Each animation begins when the previous one is 90% complete. I asked Pospesal about this after the talk and he confirmed my suspicions. This type of animation will always be messy: start times for each animation simply have to be calculated manually.
What Pospesal's demo app makes very clear is that effective Cocoa animation almost always involves multiple animations grouped together in interesting ways. That means that developers must not only master the tools Cocoa provides, but also train themselves to think more carefully about time.
In one of our current projects, we have already learned the importance of
CALayer's shadowPath property. Pospesal provided a nice description of this important property. Here is the gist. When adding a shadow to a view, most of the time all we really care about is the shadow around the edge of that view. By giving a shadow path to
CALayer, we dramatically reduce the computational intensity of computing that shadow. The code is simple:
[myView.layer setShadowPath: [[UIBezierPath bezierPathWithRect:myView.layer.bounds ] CGPath ] ];
After that you can set all the other shadow properties --offset, color, radius, opacity-- and your code won't overwhelm system resources. There is one important caveat here that I recently discovered. Any time the bounds of a layer changes, as in a rotation event, you have to remember to reset the shadowPath property for the layer. That means repeating the same line of code you see above after every bounds-changing event.
One of the great benefits of Pospesal's talk was seeing firsthand how timing curves can radically simplify animation. When we use
UIViewAnimationCurveEaseInOut, we're really just setting the time curve for an animation. With EaseInEaseOut, we mean to start the animation slowly, then speed up, then slow down as the animation concludes. Here is what EaseInEaseOut looks like as a timing curve.
In Pospesal's demo app, you can drag the #1 and #2 handles around to see the effects of all kinds of different timing curves. Then, when you're ready to apply the animation to a layer, simply feed in the control points for the curve, as follows:
CAMediaTimingFunction *timingFunction = [CAMediaTimingFunction functionWithControlPoints: .9 :.1 :.7 :.9]; [CATransaction setAnimationTimingFunction:timingFunction]; myView.layer.transform = CATransform3DRotate(myView.layer.transform, M_PI,0,0,1];
One more thing: Mark Pospesel is the Mobile Architect for Y Media Labs. In addition to many other products, they produce a ton of cool children's apps! You might want to check them out for kids. After all, if you're going to put an iPad app in front of a kid, it had better have effective animation!