I have a UIBarButtonItem in a UINavigationBar that has some custom appearance attributes (custom font, color). It appears normally most places throughout the app.
However, when a UIAlertController with the ActionSheet style is presented over the view controller with this button, the BarButton loses its custom font appearance, leading to a strange looking "jump" on the button and an incorrect font being displayed, as can be seen here: http://giphy.com/gifs/puopiq9mPyI2Q/html5 .
I assume this is likely related to how we are setting the BarButton appearance, with the following code in AppDelegate:
NSDictionary *btnAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[UIColor whiteColor],NSForegroundColorAttributeName,
[AppearanceConstants mediumFontSize20], NSFontAttributeName,nil];
[[UIBarButtonItem appearance] setTitleTextAttributes:btnAttributes forState:UIControlStateNormal];
My guess would be that the bar button is not in UIControlStateNormal, however it doesn't seem like theres anyway for me to tell what state the BarButton is in when the AlertController is presented, and just trying to set the title text attributes to the appropriate values for every control state didn't work either.
When I navigate to other view controllers with BarButtonItems in their NavigationBars after doing this, they still have the correct appearance and if I go back to the problematic screen afterward it will have the correct appearance, until the AlertController is presented again.
I reset the style after presenting the ActionSheet
UIAlertController *alertVC = ...
[self presentViewController:alertVC animated:YES completion:^{
[self.navigationItem.leftBarButtonItem setDefaultAppearanceForSpecificItem];
[self.navigationItem.rightBarButtonItem setDefaultAppearanceForSpecificItem];
}];
I created a category on UIBarButtonItem to help me
[self setTitleTextAttributes:#{
NSFontAttributeName: [UIFont systemFontOfSize:14],
NSForegroundColorAttributeName: [UIColor VKBlueColor]
}
forState:UIControlStateNormal];
Related
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.
iOS 7.0 and up.
In AppDelegate.m, I'm setting my global tintColor: self.window.tintColor = myGlobalTintColor;.
In my table view controller where I want a red trash can button in the navigation bar while editing the table view cells, I have this:
- (void)setEditing:(BOOL)editing animated:(BOOL)animate {
[super setEditing:editing animated:animate];
if (editing) { // Start editing
self.deleteBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:#selector(deleteButtonPressed)];
[self.deleteBarButtonItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor redColor], NSForegroundColorAttributeName, nil] forState:UIControlStateNormal];
self.navigationItem.rightBarButtonItems = #[self.deleteBarButtonItem];
}
}
Despite the line of code that is setting NSForegroundColorAttributeName to [UIColor redColor], I never see the red color. When the button it set to .enabled = YES, I simply see it in my global tint color, like all the other buttons:
I've combed through my code and I'm sure there are no other locations where I'm setting anything else to myGlobalTintColor. It's worth noting that this UITableViewController is instantiated from a storyboard. Commenting out the line in AppDelegate.m just sends everything back to the default blue tintColor, but I still don't get the red color on the delete button.
It turns out the problem was that I was using a third party library, SDCAlertView, and I was setting
[[SDCAlertView appearance] setTintColor:globalTintColor];
For some reason, this caused all of my UINavigationBar objects to take on it's tintColor.
I fixed this by simply replacing the above code:
[[SDCAlertView appearance] setButtonTextColor:globalTintColor];
Earlier I used a navigationcontroller with this code :
self.navigationItem.title = #"News";
Now I have the problem that I no longer needed the navigationcontroller as I am using a page controller for navigation. Now I added a navigationbar however it doesn't change the title with this code anymore.
Also how can I change the background color?
IN iOS 7 use write following code in didFinishLaunchingWithOptions
if ([[UINavigationBar class] respondsToSelector:#selector(appearance)])
{
[[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed: 4.0/255.0 green:173.0/255.0 blue:214.0/255.0 alpha:1.0f ]]; //// change background color of navigationBar
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]]; /// set backButton color of navigation bar
[[UINavigationBar appearance] setTitleTextAttributes:#{NSForegroundColorAttributeName : [UIColor whiteColor]}]; // set title color
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor], UITextAttributeTextColor,nil] forState:UIControlStateNormal]; /// set all barButton item color
self.navController.navigationBar.translucent = NO;// set translucent NO
}
Use as per your requirement.
So there is some magic happening when you use a navigation controller that you don't see and now that you've made the switch to justing using a navigation bar you lose that magic.
Navigation bars are responsible for managing and presenting UNavigationItems, and as such hold an array of them. A NavigationItem holds things like left and right buttons, and the title or titleView. When your navigation controller pushes a new controller, it creates a brand new UINavigation item then links it to your new view controller, and then pushes that onto navigation bars stack of nav items. That's why from within your view controller you set the title with self.navigationItem.title instead of referencing the navbar.
Basically you have to manage the bar and nav items yourself now. This should about do it for you:
_navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, yOffset, CGRectGetHeight(size), height)];
_navItem = [[UINavigationItem alloc] initWithTitle:#"My navbar title"];
[_navBar setItems:#[_navItem]];
[self.view addSubview:_navBar];
Of course you'll have to manage the size a bit differently as my example comes from an app where it's being used in landscape mode.
I have a simple storyboard containing a navigation controller with a static table view controller. I have added a view controller and connected it to one of the cells via a push segue. One thing I have noticed is that the navigation bar title doesn't center properly vertically with the back button and UIBarButtonItem.
Here is an image of what it looks now.
Notice that it is all aligned to the bottom. What I want is, is a way to either move the title down or move the buttons up. If the buttons were moved up, the back button arrow should be moved as well, and allow to return to the main table view.
Here is the code I'm using to set the UIBarButtonItem font in the view controller (If it helps) :
[clearButton setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:#"ChalkboardSE-Regular" size:15], NSFontAttributeName, [UIColor whiteColor], NSForegroundColorAttributeName, nil] forState:UIControlStateNormal];
And here is what I'm using to set the font for the back button in the app delegate, didFinishLaunchingWithOptions::
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor], NSFontAttributeName:[UIFont fontWithName:#"ChalkboardSE-Regular" size:15]}forState:UIControlStateNormal];
You can move the title down using: [[UINavigationBar appearance] setTitleVerticalPositionAdjustment:(float) forBarMetrics:UIBarMetricsDefault];
SWIFT version for iOS 8+
self.navigationController!.navigationBar.setTitleVerticalPositionAdjustment(adj, forBarMetrics: .Default)
self is a UIViewController:
Note: Consider specifying adjustments for the other bar metrics options, to refine the offset for landscape mode and compact devices, because one offset may not look right on all phones in all positions.
To move title down :
self.navigationController!.navigationBar.setTitleVerticalPositionAdjustmen(+Value, forBarMetrics: .Default)
To move title up:
self.navigationController!.navigationBar.setTitleVerticalPositionAdjustmen(-Value, forBarMetrics: .Default)
In swift 5:
self.navigationBar.setTitleVerticalPositionAdjustment(ajustment, for:.default)
I have a reference of UIViewController. From that reference i want to get references to all my navigation bar and bar button items and apply custom styles on them.
How can i achieve this on iOS 5?
You can do something like that.
[backbutton setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor blackColor],UITextAttributeTextColor,[UIFont fontWithName:TEXTFONT size:16.0f],UITextAttributeFont,
nil] forState:UIControlStateNormal];
Assuming your view controller has a navigation controller, you should be able to access the navigation bar and its items using the following code:
UINavigationBar *navBar = [myViewController.navigationController.navigationBar];
NSArray *navBarItems = navBar.items;