Each UIViewController has its own UINavigationItem property that is pushed or popped by a UINavigationBar object that lays out navigation bar at the top of the view.
I had two goals. 1) Drop custom left and right bar button items and custom text on the navigation bar and 2) Customize the animations between the navigation items in the navigation bar. So I needed to sub-class UINavigationBar for 2). And I needed to create a custom UINavigationItem that I could reuse everywhere and give the app a consistent look and feel. This would satisfy 1).
My customization for the animations basically required that the navigation bar would not animate the transition between UINavigationItem objects:
- (UINavigationItem *) popNavigationItemAnimated:(BOOL)animated { return [super popNavigationItemAnimated:NO]; } // why isn't this getting called, though? this will be a source of issues to be resolved later - (void) pushNavigationItem:(UINavigationItem *)item animated:(BOOL)animated { [super pushNavigationItem:item animated:NO]; }
The next step was to subclass UINavigationItem to be used in all of my view controllers that were managed by my parent UINavigationController. This would be a bit tricky because the navigationItem property of a UIViewController is read-only; however, Apples does give us a way to customize it:
Which is precisely what I did. But the funny thing about customizing a UINavigationItem is that most everything has to be manually created for the bar button items - including their target/action pair.
/* set the back icon */ UIImage *homeImage = [UIImage imageNamed:@"homebaritem_24x24_v4.png"]; UIBarButtonItem *homeBarButtonItem = [[UIBarButtonItem alloc] initWithImage:homeImage style:UIBarButtonItemStylePlain target:navController action:@selector(popViewControllerAnimated:)]; [self setLeftBarButtonItem:homeBarButtonItem];
It was the last two highlighted lines that turned out to completely bypass my custom UINavigationBar's overriden methods above (why???) which meant that the animations were happening somewhere in the code that I could not intercept and modify.
Great. Got my custom visuals, but now they don't animate the way I want.
So after reading through Apple's documentation, trying to see what hooks I could use, I finally stumbled upon the navigationController: willShowViewController: animated: method on the UINavigationControllerDelegate protocol. Here's my hackalicious work-around to get what I wanted:
// we implement this optional method so that we can hide and unhide the navigation bar // such that the animation fade in/out transition of the bar is negated. we do it in the // willshow because testing on the simulator found this was where the effect would // actually work // potential future pitfall: hiding the nav bar might actually collapse it and thus may shift views upwards?? - (void) navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { // this SEEMS hacky. probably is. not sure. but it works for now. [navigationController setNavigationBarHidden:YES animated:NO]; [navigationController setNavigationBarHidden:NO animated:NO]; }
It turns out that the animation timings work out so that if I make the navigation bar hidden then shown instantaneously, it overrides the default fade in/fade out animation of navigation item transitions, but is fast enough so that the human eye cannot see the visibility transitions.
And, of course, this is only on the simulator so far. Who knows what will happen when I push this to a device. Or when the next version of the iOS SDK comes out.
I'll cross that bridge when I get there, I suppose.
No comments:
Post a Comment