views:

2162

answers:

4

Hello.

I'm basically trying to duplicate the behavior of the iPod app on the iPhone, where when you select a song, the music player view slides in, and the navigation bar transitions to a new color.

My app is set up as a tabbed based application, with UITabBarController and a nested UINavigationController in each tab. Inside each UINavigationController for each tab is a UITableView. When I select an item in the table, I'm using pushViewController to slide to the next view, and I've set hidesBottomBarWhenPushed in the next view controller in order to slide the tabs away. The behavior is very close to the iPod "Now Playing" page, which is nearly perfect.

The final problem is that I'm unable to transition the color of the navigation bar, like how the navigation bar in the iPod app fades from blue to black. I'm able to force the color change after the new view appears (in viewWillAppear), but the change is abrupt and does not mimic the behavior of the iPod app, with a fade effect.

Does anyone know what I'm missing here? It seems like a very simple and common UI that I've seen in several applications, but there doesn't appear to be an obvious way to do it.

A: 

Take a look at UIView's animation methods and CAAnimation. They are both well documented in the SDK.

Note that you may not be able to achieve the effect you want without adding some custom graphics.

Roger Nolan
+1  A: 

You can animate the status bar style change to create an effect that's pretty close.

- (void)viewWillAppear:(BOOL)animated {
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:animated];
    self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
}

As you've noticed the navigation bar style changes immediately, but the animated change to the status bar still provides the overall appearance of a transition.

Matt Stevens
That's what I actually went with, and the effect is satisfying enough.
Steve Simitzis
Thanks. Only comment, remember if you override `viewWillAppear`, you must call super at some point in your implementation.
petert
+1  A: 

I cooked a solution that might be more what you're looking for.

  • Create a custom subclass of UINavigationBar.
  • Override setBarStyle: as follows

code:

- (void)setBarStyle:(UIBarStyle)style {
    //Fade our content, ie background, from one style to another
    CATransition *transition = [[CATransition new] autorelease];
    transition.type = kCATransitionFade;
    transition.duration = 0.2;
    [self.layer addAnimation:transition forKey:@"content"];

    [super setBarStyle:style];
}
  • Configure your nav controllers to use this subclass
    • In IB, you can just set the class in the inspector
Andrew Pouliot
+3  A: 

Andrew's answer actually works pretty well, but I would add two things to make it work better:

  1. Provide the functionality via a category instead of subclassing. Much, much less messy.
  2. Only use the transition when absolutely necessary. The reason for this is that when using this technique, the original title text just fades away instead of also sliding off the side. It's subtle, but much more noticeable if it happens during a transition where the bar style isn't actually changing. So I avoid that case.

Here's my category code (I have it in categories of both UINavigationBar and UIToolbar):

- (void)setBarStyle:(UIBarStyle)barStyle animated:(BOOL)animated {
    if (animated && self.barStyle != barStyle) {
        CATransition *transition = [CATransition animation];
        transition.duration = 0.2;
        transition.timingFunction = [CAMediaTimingFunction
            functionWithName:kCAMediaTimingFunctionEaseIn];
        [self.layer addAnimation:transition forKey:nil];
    }

    [self setBarStyle:barStyle];
}

And this is how I use it:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [[UIApplication sharedApplication]
        setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
    [self.navigationController.navigationBar
        setBarStyle:UIBarStyleBlackTranslucent animated:YES];
    [self.navigationController.toolbar
        setBarStyle:UIBarStyleBlackTranslucent animated:YES];
}
Hilton Campbell