I am having an issue with some odd rendering behaviour on iOS as the screenshot below will illustrate.
The layout architecture for my app is as follows:
I have a main view controller that contains a tab bar controller and a standard UIViewController as child view controllers.
The tab bar controller is the main thing the user sees and when there is a pan gesture across the navigation bar, it reveals the second view controller as a menu view controller. Pan to reveal.
I have a tab bar controller which contains a series of tabs, each one containing a navigation controller.
Each of these navigation controllers contains a view controller.
The problem happens when I have pushed another view controller onto one of the navigation controllers - where the back button appears. At all other times everything is ok.
Has anyone else encountered this issue before? I am using the appearance proxy for setting the colours on the tab bar and navigation controllers.
It turns out that I had to set the translucency of the NavigationBar and the Tab bar to NO and this seems to have fixed it.
In my Tab Bar controller I added the following line to viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
[self.tabBar setBarTintColor:[UIColor whiteColor]];
[self.tabBar setTintColor:[UIColor redColor]];
[self.tabBar setTranslucent:NO];
}
In my NavigationController I added the following to viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
[self.navigationBar setTranslucent:NO];
}
Hope this helps others who have had the same problem.
Related
I want a transparent black theme throughout my iOS app on both navigation bars, tab bars, and toolbars (I use all 3), and I have this set up through storyboards. I have a subclassed tabbar controller that presents a sign up modal with a navigation controller programmatically as follows:
UserSignUpViewController *userSignUpViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"UserSignUpViewController"];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:userSignUpViewController];
userSignUpViewController.delegate = self;
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:navigationController animated:YES completion:nil];
this is called in my subclass tabbars view did appear, so I can see that my tabbar shows up as translucent black before this animates up modally. when I dismiss this sign up navigation controller, the tabbar reverts to "opaque" meaning solid white. Why is this happening and how do I fix it?
The tab/navigation bar tint colors that I set in my appdelegate persist but the translucent styling of the bars gets reset for some reason. I should add that if I don't display the sign up view controller (user is already signed in), then the tab bar is the correct styling. Thanks!
It could be because you are calling it in viewDidAppear instead of viewDidLoad
After reading a bunch of similar questions on SO I've found out that in order to use a custom back button view I should be setting the nav controller's nav bar's nav item's left button item to a custom view, but no matter what I do I'm getting stuck with the default. I've tried setting this both inside the view controller I want to navigate back from, as well as the one I'm navigating back to, to no avail. Any ideas what I might be doing wrong?
- (void)loadView{
[super loadView];
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc]initWithCustomView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"back-btn"]]];
self.navigationController.navigationItem.leftBarButtonItem = backButtonItem;
self.navigationController.navigationItem.leftBarButtonItem.tintColor = [UIColor whiteColor];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
The key thing you’re doing wrong is using the bar button item on the navigation controller instead of on your view controller. To quote Apple’s View Controller Catalog for iOS:
In a navigation interface, each content view controller in the navigation stack provides a navigation item as the value of its navigationItem property.
Emphasis mine; the content view controller is your custom view controller. Try this:
self.navigationItem.leftBarButtonItem = backButtonItem;
You need to do this in all your view controllers that should have the custom button, so I recommend creating your own base view controller class that subclasses UIViewController and implements custom back buttons, and use this base view controller as the parent of your other view controllers.
You’re hiding the navigation bar, which probably isn’t a good idea if you want it to show a custom back button.
By replacing the standard back button, you lose its tap behaviour. Use a UIButton in the bar button item’s custom view instead of a UIImageView.
Also, it would be more conventional to put this setup code in viewDidLoad rather than loadView.
So I would do something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
[backButton setBackgroundImage:[UIImage imageNamed:#"back-btn"] forState:UIControlStateNormal];
[backButton sizeToFit];
[backButton addTarget:self action:#selector(popNavigationController:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
self.navigationItem.leftBarButtonItem = backButtonItem;
}
- (void)popNavigationController:(id)sender
{
[[self navigationController] popViewControllerAnimated:YES];
}
Note that if you use a custom back button, the swipe-from-the-edge-of-the-screen-to-go-back gesture will not work. See this Stack Overflow question for a couple of potential solutions, but it’s fiddly.
I have a custom toolbar that I am implementing in my app. I am using a navigation controller for my views. In my first view I have:
- (void)viewDidLoad
{
// Background toolbar image for every View
UIImage *image = [UIImage imageNamed:#"toolbar_iphone1.png"];
[[UIToolbar appearance] setBackgroundImage:image forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
}
The first time the view is shown, the toolbar is the default one and not my custom toolbar. All the views after that have the custom toolbar though. And if I go back to that original view, then the toolbar shows up.
Any ideas as to why this is happening?
You are not calling [super viewDidLoad] in your implementation.
Add it and try again.
I'm showing UINavigationController modally.
For the root view controller, I don't want to show the Navigation bar.
However for deeper controllers, I do want to show it.
I though of doing something like this inside my root view controller :
-(void) viewWillAppear:(BOOL)animated
{
[self.navigationController.navigationBar setHidden:YES];
}
-(void) viewWillDisappear:(BOOL)animated
{
[self.navigationController.navigationBar setHidden:NO];
}
However, this presents issues, when I go back from the first view controller to the root view controller.
The navigation bar is disappearing after pressing the "back" button (inside the first view controller, leaving white space), and not only after the rootViewController finished loading. (Obviously because my code uses viewWillAppear)
Is there a solution for it ?
The only thing I thought of is hidiing the navigation bar permanently, and adding Navigation bar manually to each view controller in the stack.
I hope not to do that since it's much more work, and moreover, I want to use arrow shaped buttons, for which I would have to create custom images.
Appreciate any suggestions.
This should do it, I haven't tested it out, but should work in theory:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:YES];
}
I am having trouble with my navigation toolbar. I set the navigation toolbar background image in my app delegate, and then have a button that, when clicked, changes the navigation tool bar background image and moves to another view.
This works fine, however, when I hit the back button, and go back to the original view, the navigation toolbar background image does not change back.
Here is the relevant code:
In my first view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
//set to change the navigation toolbar to this background image (the first) when this view loads
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"QuickGrocery Logo Updated.jpg"] forBarMetrics:UIBarMetricsDefault];
}
button action:
- (IBAction)wellBalancedMealsClicked:(id)sender {
QuickGroceryMasterViewController *masterViewController = [[QuickGroceryMasterViewController alloc] initWithNibName:#"QuickGroceryMasterViewController" bundle:nil];
[masterViewController setRecipeChoice:1];
//changes the navigation toolbar background image
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"Keep It Balanced.jpg"] forBarMetrics:UIBarMetricsDefault];
}
There's just one image for the navigation bar. If you change it, and later you want it to change back, you have to change it back yourself.
I'd suggest you give each of your view controllers a navigationBarImage property. Set a delegate for your navigation controller. In the delegate, add this method:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
UIImage *image = [(id)viewController navigationBarImage];
if (image)
[navigationController.navigationBar setBackgroundImage:image forBarMetrics: UIBarMetricsDefault];
}