Navigation bar appearance doesn't change after a first setting - ios

I set a certain vertical offset for the navigation bar's title when the app becomes active:
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:-3.0f forBarMetrics:UIBarMetricsDefault];
Then, later in the navigation hierarchy, I need to set a different vertical offset, so I call:
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:-0.5f forBarMetrics:UIBarMetricsDefault];
But I find that the new vertical offset is not applied when I navigate being the app active. However, if app becomes inactive and then active again, it is applied. How can I change this offset while the app is kept in foreground?
Thanks!

From https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIAppearance_Protocol/index.html
iOS applies appearance changes when a view enters a window, 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.
So basically you need to do some HACK to remove the view and then immediately add it back, something like this...
UIView *currentview = ((AppDelegate*)[UIApplication sharedApplication].delegate).window.rootViewController.view;
UIView *superview = currentview.superview;
[currentview removeFromSuperview];
[superview addSubview:currentview];
And for Swift...
if let currentview = (UIApplication.sharedApplication().delegate as? AppDelegate)?.window?.rootViewController?.view {
if let superview = currentview.superview {
currentview.removeFromSuperview()
superview.addSubview(currentview)
}
}

Did you try doing this with animation block?
[UIView animateWithDuration:3
animations:^{
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:-3.0f forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:-0.5f forBarMetrics:UIBarMetricsDefault];
}];

Related

Show transparent UINavigationbar will see black bar when swipe the viewController

I have a UINavigationController with 3 viewControllers. We know the three viewControllers share a common navigationBar.If I want to set the navigationBar totally transparent. I can put the code in viewWillAppear:
[self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setShadowImage:[UIImage new]];
[self.navigationBar setBarTintColor:[UIColor clearColor]];
self.navigationBar.translucent = YES;
and set it back in viewWillDisappear:
[self setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self setShadowImage:nil];
[self setBarTintColor:THEME_COLOR];
self.translucent = NO;
I want to set the UINavigationBar translucent only in viewControllerB, so I put the code in viewControllerB. However, when I popToViewController B, I can see a black bar in the top right of the screen. Since the viewWillAppear is invocated. It seems can not be solved in my case.
I come out with some methods:
use different UINavigationBar.
use different UINavigationController. But UINavigationController can not push a new UINavigationController
Custom UIView like UINavigationBar.
I think above methos is more complicated。
Any ideas thanks!
That black color you see is the background color of main window. You can set background image or color to your main window from AppDelegate didFinishLaunchingWithOptions method (That's totally depends with your design of the view controller B) so that you won't see any difference.
Or else
Simply you can use viewDidAppear instead of using viewWillAppear, but that will have little flick though.

How to make two different barTintColor present for one navigationBar in a pop/push transmition

Some normal code looks like this:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController.navigationBar setBarTintColor:someColor];
}
or
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController.navigationBar setBarTintColor: someColor];
}
However, this causes the navigation bar suddenly and completely change it's color upon push event occurs. (or upon you drag the left edge of a controller to pop it, which triggers 'viewWillDisappear' method) Is there any way that I can keep both color presenting during the pop animation?
I know weChat can do that...
As the photo below, while the controller at right side is being popped, the light gray background color (maybe background image) of it's navi bar is there, and the black color of the navi bar of the controller at left side is also there.
I solved it by making the the navigation bar transparent in both views, and I added the colors I want in the views itself with a rectangular view just for this to use as background color.
here the storyboard:
and here the final result:
Some code (make sure you don't hard code the width of the view like in this example):
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
UIView *bg = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 480, 60)];
bg.backgroundColor = [UIColor redColor];
[self.view addSubview:bg];
And make sure you disable "Adjust ScrollView Insets"

How to change the background color of navigation bar in a modal view?

I present a modal view when I click a cell in my custom tableview. How to change the background color of navigation bar in a modal view?
For example. I want to change it to black color.The following code do not work in the prepare segue method.
[destinationNavController.navigationBar setBackgroundColor:[UIColor blackColor]];
or
[[UINavigationBar appearance]setBackgroundColor:[UIColor blackColor]];
or
[destinationNavController.navigationBar setTintColor:[UIColor blackColor]];
in the viewDidLoad method of the destination Controller view I write
[self.navigationController.navigationBar setBackgroundColor:[UIColor blackColor]];
or
[[UINavigationBar appearance]setBackgroundColor:[UIColor blackColor]];
or
[self.navigationController.navigationBar setTintColor:[UIColor blackColor]];// only change the navigation item text color....
Any other ideas?
This the right way to present the modal controller and change the nav bar color, write the below code:-
[self presentModalViewController:customViewController animated:YES];
customViewController.topViewController.navigationController.navigationBar.tintColor = [UIColor blackColor];
If you are on ios 7 or later, you need to use the barTintColor property of UINavigationBar.
Like this:
self.navigationController.navigationBar.barTintColor = [UIColor blackColor];
I only tested this in iOS 11 so far and in my case our app is white but I want to present a fullscreen slide show with black color, but I still wanted a status bar, with white letters and the same black background as my main view
Step 1: make your view background color black.
XCode in your .xib or storyboard the parents view's background color black (very important step)
Step 2:
in your view controller that is in charge of this view, add this:
override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent }
This makes the color of the status text to be white. This also works on iPhone X.

Buttons on navigation bar do not pick up window tint colour

Note, I've recently come back to this and it seems to have been fixed in more recent versions of the SDK, without me having to implement anything except the code in the question. Many thanks to all who answered.
I have an Objective-C app that runs on the iPad and displays a view controller with a modal presentation style of UIModalPresentationPageSheet:
UINavigationController *editorNavigationController = [[UINavigationController alloc] initWithRootViewController:editorViewController];
editorNavigationController.modalPresentationStyle = UIModalPresentationPageSheet;
[navigationController presentViewController:editorNavigationController animated:YES completion:nil];
When this view controller is displayed the buttons in the navigation bar are purple, which I assume has been picked up from the window's tint colour, which is what I want.
Later I need to display another view controller over the top, that fills the whole window:
UINavigationController *previewNavigationController = [[UINavigationController alloc]initWithRootViewController:myPreviewViewController];
[owningViewController presentViewController:previewNavigationController animated:YES completion:nil];
The problem I have is that when myPreviewController is displayed, the buttons in the navigation bar are grey. I've tried reinstating the colour on the new navigation controller:
previewNavigationController.navigationBar.tintColor = [UIColor colorWithRed:123/255.0 green:26/255.0 blue:69/255.0 alpha:1];
but without any joy.
How can I get the buttons to have the correct colour? Can I get the new navigation controller to pick up the window tint colour automatically, or do I have to set it explicitly? Is this something to do with presenting the second navigation controller over the top of one that uses UIModalPresentationPageSheet?
Any help much appreciated! Thanks,
Paul
You can set the navigationBar translucent and transparent.
In view Will Appear:
self.navigationController.navigationBar.translucent = NO;
Than create a UIView with frame size of navigationBar (CGRectMake(0,0,self.view.frame.size.height,22) and create buttons on it with color you need.
I know, thats a crutch but should work)
You can change the appearance of the UIBarButtonItem globally so all UINavigationControllers will share the same design:
[[UIBarButtonItem appearance] setTintColor:[UIColor purpleColor]];
[[UIBarButtonItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"fontName" size:16.0f],NSFontAttributeName,
nil] forState:UIControlStateNormal];
Additionally you could also change the [UINavigationBar appearance]:
//The setTintColor would tint the < Back button in the NavigationBar
[[UINavigationBar appearance] setTintColor:[UIColor greenColor]];
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
[[UINavigationBar appearance] setTitleTextAttributes:
#{NSForegroundColorAttributeName:[UIColor blueColor]}];
This code can be add it before presenting the UIViewControllers or simply in the AppDelegate.m.

UINavigationBar appearance refresh?

In my iPad app I have an application settings view. One of the options lets the user switch interface color scheme. The settings view is loaded by segue to a separate view controller than my "main" app's window.
When they pick a new color I switch the colorSchemeColor variable and do this:
// set the colors and refresh the view
[[UINavigationBar appearance] setBarTintColor:colorSchemeColor];
[[UIToolbar appearance] setBarTintColor:colorSchemeColor];
[[UITabBar appearance] setBarTintColor:colorSchemeColor];
However, none of the bars change color until I exit my settings view! (When the settings window disappears, the colors for the "main" app change correctly!)
So then I tried to put this code right after to refresh the settings view:
[self.view setNeedsDisplay];
[self.view setNeedsLayout];
which didn't help. So I added this as well:
[self.navigationController.view setNeedsDisplay];
[self.navigationController.view setNeedsLayout];
This didn't work either.
How can I get my settings view to "redraw" itself when the new color is picked so the change is instantly obvious?
Thanks so much!
The appearance proxy only affects the look of newly initialized views. Setting colors on the appearance proxy will have no effect on navigation bars that are already visible.
You'll need to manually update your current view; for example:
self.navigationController.navigationBar.barTintColor = [UINavigationBar appearance].barTintColor;
Objective-C:
self.navigationController.navigationBarHidden = YES;
self.navigationController.navigationBarHidden = NO;
Swift:
self.navigationController?.isNavigationBarHidden = true
self.navigationController?.isNavigationBarHidden = false
While I think Aaron Brager's answer is the ideal appraoch, my app needs about 15 different appearance settings and uses a split view controller, so I have to reapply all the setting to the global appearance and then apply them all to my two displayed views. That's a lot of redundant code.
Based on the idea that presenting and dismissing a modal view controller forces everything below it to redraw, I tried this and it worked perfectly:
UIViewController *redrawTrigger = [[UIViewController alloc] init];
redrawTrigger.modalPresentationStyle = UIModalPresentationFullScreen;
[mySplitViewController presentModalViewController:redrawTrigger animated:FALSE];
[mySplitViewController dismissModalViewControllerAnimated:FALSE];
[redrawTrigger release];

Resources