Entries in Code (3)
For the last 6 months, I've had the good fortune to work on a number of awesome projects. Things that I would love to show to other people and brag about, but I always hesitate because they aren't unconditionally awesome--and they aren't all mine.
As part of my contracting gig, I've jumped into a number of projects that were about 75% finished. My job was to polish them up and get them ready for the app store. While I'm really proud of the work I've done, there are several lingering problems that I really wish I could go back and "do right." Most of these are existing features that worked (more or less), and we just didn't have the time or money to fix.
There were also a number of management-level decisions that I didn't entirely agree with. Things like the way we handled in-app ads. I mean, I understand. My client needs to make money. Hell, I want them to make money. After all, I want them to keep paying me. But, it would have been nice if we could have toned things down a bit. Still, they asked for it; I implemented it. No shame in that.
Mostly, though, I don't want to look like I'm taking credit for someone else's work. After all, they lead the horse to water--I just got it to drink. Or, in other words, I didn't make it, I just made it awesome.
The really weird thing is that this uneasy feeling goes cuts other way as well. I often find myself having trouble talking to my clients, especially when things start to go wrong.
I mean, I don't want to be THAT guy. You know the one. The guy who is always whining about the last person who had his job. Always finding some way to blame them or excuse his poor performance on them. In an ideal world, I want to be the one who finds the problems, owns the problems and fixes the problems. But when my clients are pestering me for results, and I'm fighting to meet a tight deadline, and I just spent the last 15 hours cleaning up someone else's mess...well, it's hard to find a constructive way to express my concerns. I mean, let's be honest, (and I'm sure Obama would have my back here) sometimes it really is the Bush Administration's fault. Or in my case, it's the fault of whatever knuckle-typing orangutan they hired to cobble this thing together.
Don't get me wrong, I love a good orangutan. But, let's face it, they are the hippies of the simian world. If you need a sidekick to ride on your hog and watch your back at the roadhouse, then a orangutan is definitely the way to go. But, despite the convincing neck beard, they should not be allowed anywhere near code.
And I guess that's the real lesson here. Don't hire orangutans. They may work for bananas, but eventually you'll have to hire someone like me to come in and shovel out their poop. In the long run, those will become the most expensive bananas you've ever purchased.
I love the UINavigationController class for iOS. It's a great framework for managing a wide range of view-swapping applications, and we get the transition between views for free.
But, what if we want to use a different type of transition animation? UINavigationController only has one option--the new view slides in from the right while the old view slides off the left. There's no direct mechanism, but it turns out that it's not too hard to manage, at least for a select set of transitions.
First, lets look at the UIView methods. The navigation controller has its own view, which will contain the subviews we wish to manage. in iOS 4.0 and later, we can use that view's block-based animation.
Note: when we actually call pushViewController: we are setting the animated value to NO. This disables the Navigation Controller's default animation. Instead, the block of code uses the defined transition (in this case UIViewAnimationOptionTransitionCurlDown).
The same thing can be done using iOS 2.0 or later (although, you cannot submit anything older than 2.0 at this time).
[UIView beginAnimations:@"transition" context:nil];
Also notice, the two methods use two slightly different constants to define the view type. However, they both support the same four options: curl up, curl down, flip left and flip right.
We can get a different set of transitions by setting a transition animation for the Navigation Controller's view's Core Animation Layer.
CATransition* transition = [CATransition animation];
transition.duration = 1.0;
transition.type = kCATransitionFade;
transition.subtype = kCATransitionFromTop;
There's one big difference here. The other animations were local. They only affected the code within the block (or between the beginAnimations and commitAnimations calls). This is a global change, and will continue to affect the Navigation Controller's behavior until it is changed again (or cleared by setting the animation to nil).
This also has four options: fade in, move in, push or reveal. For all but the fade, you can also set the direction of motion (from the top, bottom, left or right--though the iPhone seems to reverse the top and bottom options). We've already seen the push animation--the default behavior is a push from the right. Move in simply slides the new view over the existing one. Reveal pulls the old view away, revealing the existing one. While fade simply cross-fades from one view to the next.
I really wish there was an easy way to do other animated transitions (for example, having a view appear to grow from the center of the screen, or shrink into the center of the screen). But, I suspect those would take a lot of work at the CALayer level. I made a few attempts using regular animation blocks and altering the size of the incoming view. I could get the size to animate, but the old view simply vanished, leaving my new view to appear over a white background. Not what I wanted at all.
Still, there's a lot of cool effects you could produce with just these options. Happy hacking!