Updating navigation bar after a change using UIAppearance
Asked Answered
R

3

7

I'm currently customising the navigation bar background image of my iOS app using the UIAppearance proxy. There is a button for switching between two different modes which triggers a notification. This notification will change the background to a different image using again the proxy. My problem is that this change becomes visible only when I go to a different controller and I come back to it. I'm not able to force the update of the navigation bar within the controller.

I've tried this in my MainTabBarController:

- (void) onAppChangedMode: (NSNotification*)notif {

APP_MODE mode = (APP_MODE) [[notif object] integerValue];

// change navigation bar appearance
[[UILabel appearance] setHighlightedTextColor:[UIColor redColor]];
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:(mode == 0 ? @"navbar.png" : @"navbar2.png")] forBarMetrics:UIBarMetricsDefault];
// trying to update
for (UIViewController* vc in self.viewControllers) {
     [vc.navigationController.navigationBar setNeedsDisplay];
}

}

but nothing...it's not working. Any idea how to achieve it?

Thanks!

Rafe answered 22/2, 2013 at 12:14 Comment(7)
I don't know why, but the changes to uiappearance at runtime won't apply to any loaded views. However, you can immediately apply the changes on the loaded views themselves.Clarence
does it mean I cannot use UIAppearance but I have to set each bar separatelyRafe
No. You can use UIAppearance but the displayed views won't be affected. So the one displayed bar you should set explicitly.Clarence
I wonder if it's a bugRafe
I don't think so. UIAppearance is a convenient way to specify the appearance of your whole app, a task that typically is done once at app startup.Clarence
I agree,but this limitation makes the whole visual context switching quite cumbersome.Rafe
Can you reply to the question not in comment? I think your answer it's the correct one and I would like to assign it to you.Rafe
C
0

Try this code to change the background image for the current nav bar only:

[self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];

Use the above code after changing the UIAppearance. This will force a change in the nav bar of the current controller. The nav bars for the other controllers will be handled by the change in UIAppearance.

Cinthiacintron answered 23/2, 2013 at 0:4 Comment(1)
edited my answers. Use the above code TOGETHER with your code in changing the UIAppearance.Cinthiacintron
A
13

Just remove views from windows and add they again:

for (UIWindow *window in [UIApplication sharedApplication].windows) {
    for (UIView *view in window.subviews) {
        [view removeFromSuperview];
        [window addSubview:view];
    }
}
Arredondo answered 2/2, 2015 at 9:26 Comment(2)
This works perfectly for me. It doesn't appear to have any performance issues and is effective immediately.Knock
As per Apple's docs: developer.apple.com/documentation/uikit/uiappearance: iOS applies appearance changes when a view enters a window, but it doesn’t change the appearance of a view that’s already in a window. To change the appearance of a view that’s currently in a window, remove the view from the view hierarchy and then put it back.Carmichael
P
7

I just have the same problem, this code will help you:

- (IBAction)btnTouched:(id)sender {
    [[UADSwitch appearance]setOnTintColor:[UIColor redColor]];

    // Present a temp UIViewController 
    UIViewController *vc = [[UIViewController alloc]init];
    [self presentViewController:vc animated:NO completion:nil];//"self" is an instance of UIViewController
    [vc dismissViewControllerAnimated:NO completion:nil];
}
Pinzler answered 27/5, 2013 at 7:25 Comment(1)
+1 Used your method and got a warning/problem with my UITabBarController: Warning: Attempt to present <UIViewController: 0x83ea6e0> on <MNCalendarsTabBarControllerViewController: 0x86861a0> whose view is not in the window hierarchy!. So I modified your solution by replacing self with UIViewController *presentingController = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; [presentingController presentViewController: viewController animated: YES completion: nil];, found here - and it worked. Tanks, took me hours.Yuriyuria
C
0

Try this code to change the background image for the current nav bar only:

[self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];

Use the above code after changing the UIAppearance. This will force a change in the nav bar of the current controller. The nav bars for the other controllers will be handled by the change in UIAppearance.

Cinthiacintron answered 23/2, 2013 at 0:4 Comment(1)
edited my answers. Use the above code TOGETHER with your code in changing the UIAppearance.Cinthiacintron

© 2022 - 2024 — McMap. All rights reserved.