2

I would like to change the color of my navigation bar, with animation.

I tried CATransition but I can't find how to change the color with that.

Is there a way to change the color with a fading or any other animation ? Like TransitionDrawable in Android.

Thanks.

Pull
  • 2,236
  • 2
  • 16
  • 32
  • possible duplicate of [UINavigationBar change Tint color with animation](http://stackoverflow.com/questions/5042283/uinavigationbar-change-tint-color-with-animation) – Adrian P Dec 04 '13 at 14:53
  • In iOS7 the color of the navigation bar changes **always** animated. If you simply set the color in code there is a smooth, maybe 0.5s animation. – Marc Dec 04 '13 at 15:07
  • I already read this post, but I didn't read the second post explaining it's not possible to animate the background color... – Pull Dec 04 '13 at 15:11
  • @MarcMosby Do you know how to slow this animation for like 1 more second ? – Pull Dec 04 '13 at 15:14
  • The solution was animating the barTinTColor and not the backgroundColor ! – Pull Dec 05 '13 at 10:04

3 Answers3

3

I tried some stuff and finally ended up with this solution. It doesn't need any extra layers, images or transition views and makes use of the built-in animation of the bar.

Therefore it does not hide any titles and bar buttons that you have placed on your navigation bar. If the nav bar is below a status bar, the status bar's color will also be changed.

This is tested with iOS7, both for simulator as well as real device (iPad)

The code:

Right below your imports do

#define STEP_DURATION 0.01

You can play with this value for a smoother animation

This is the method that you want to call

[self animateNavigationBarFromColor:[UIColor greenColor] toColor:[UIColor blueColor] duration:2.5];

Parameters should be self-explaining (duration is in seconds).

And this is the actual code

- (void)animateNavigationBarFromColor:(UIColor *)fromColor toColor:(UIColor *)toColor duration:(NSTimeInterval)duration
{
    NSUInteger steps = duration / STEP_DURATION;

    CGFloat fromRed;
    CGFloat fromGreen;
    CGFloat fromBlue;
    CGFloat fromAlpha;

    [fromColor getRed:&fromRed green:&fromGreen blue:&fromBlue alpha:&fromAlpha];

    CGFloat toRed;
    CGFloat toGreen;
    CGFloat toBlue;
    CGFloat toAlpha;

    [toColor getRed:&toRed green:&toGreen blue:&toBlue alpha:&toAlpha];

    CGFloat diffRed = toRed - fromRed;
    CGFloat diffGreen = toGreen - fromGreen;
    CGFloat diffBlue = toBlue - fromBlue;
    CGFloat diffAlpha = toAlpha - fromAlpha;

    NSMutableArray *colorArray = [NSMutableArray array];

    [colorArray addObject:fromColor];

    for (NSUInteger i = 0; i < steps - 1; ++i) {
        CGFloat red = fromRed + diffRed / steps * (i + 1);
        CGFloat green = fromGreen + diffGreen / steps * (i + 1);
        CGFloat blue = fromBlue + diffBlue / steps * (i + 1);
        CGFloat alpha = fromAlpha + diffAlpha / steps * (i + 1);

        UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
        [colorArray addObject:color];
    }

    [colorArray addObject:toColor];

    [self animateWithArray:colorArray];
}

- (void)animateWithArray:(NSMutableArray *)array
{
    NSUInteger counter = 0;

    for (UIColor *color in array) {
        double delayInSeconds = STEP_DURATION * counter++;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [UIView animateWithDuration:STEP_DURATION animations:^{
                self.navigationController.navigationBar.barTintColor = color;
            }];
        });
    }
}

Drawback: It's not buttery smooth :(

Marc
  • 6,051
  • 5
  • 26
  • 56
  • Worderful, you gave my the answer I needed, barTinTColor can be animate ! But I simply need this code : self.navigationController.navigationBar.barTintColor = [UIColor redColor]; [UIView animateWithDuration:5.0f animations:^{ self.navigationController.navigationBar.barTintColor = [UIColor blueColor]; } completion:^(BOOL finished) { }]; – Pull Dec 05 '13 at 10:00
  • Are you sure you don't need more? No matter what value you choose for duration, internally it will always be the same. That's why I made an animation loop. – Marc Dec 05 '13 at 10:29
  • UIView animateWithDuration make the animation for you, you don't need an animation loop. But I was using backgroundColor instead of barTinTColor that's my mystake. – Pull Dec 05 '13 at 10:36
  • Well I wrote the code, I know what animateWithDuration does ;) But did you try your code? Did the animation really take 5 seconds? – Marc Dec 05 '13 at 10:38
  • Of course it works, I already finish adding this feature to all my tabs with 5 differents color and it's working perfectly with the duration specified. Thanks again. – Pull Dec 05 '13 at 10:44
  • What device did you try that on? On my iPad (and iPad simulator) the duration didn't work, thats why I looped. Ofc I am happy for you if the much simpler version works, but would be interesting to know why it doesn't work for me. – Marc Dec 05 '13 at 10:49
  • Ha you are right, it seems to work only on iOS 7, I got a crash in iOS 6. – Pull Dec 05 '13 at 10:54
  • iOS6 doesn't have the property `barTintColor`. You have to use `tintColor` there. You can test with `respondsToSelector:` if the property is available – Marc Dec 05 '13 at 12:35
0

Is your fading just meaning changing alpha of navigationBar, See this code:

if ([self.navigationController.navigationBar respondsToSelector:@selector(setBarTintColor:)]) {
    [self.navigationController.navigationBar setBarTintColor:[UIColor blueColor]];
} else {
    self.navigationController.navigationBar.tintColor = [UIColor blueColor];
}

self.navigationController.navigationBar.alpha = 0.f;
[UIView animateWithDuration:.2f animations:^{
    self.navigationController.navigationBar.alpha = 1.f;
} completion:^(BOOL finished) {
    //
}];
shanegao
  • 3,562
  • 1
  • 18
  • 21
  • I already tried that, but with the alpha the transition start with black, I want the transition starting with a color and finishing with another one. And my gold is to change only the background, not the entire navBar with the logo in it. But thanks for your answer. – Pull Dec 04 '13 at 15:24
0

I find a solution that I will explain here.

As we can't change the backgroundColor attribut, we will need a trick to make an animation for changing the navBar color with animation.

I choose to put above my navBar an identical subview with CATransition.

CGRect frame = self.navigationController.navigationBar.frame;
UIView *view = [[UIView alloc] initWithFrame:frame];
[view setBackgroundColor:[UIColor redColor]];
UIImageView *logo = [[UIImageView alloc] initWithFrame:CGRectMake(77,3,163,38)];
[logo setImage:[UIImage imageNamed:@"icon_transparent.png"]];
[view addSubview:logo];

CATransition *myAnimationView = [CATransition animation];
[myAnimationView setDuration:1.5f];
[myAnimationView setType:kCATransitionReveal];
[myAnimationView setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[[view layer] addAnimation:myAnimationView forKey:kCATransitionReveal];
[self.navigationController.navigationBar addSubview:view];
Pull
  • 2,236
  • 2
  • 16
  • 32