I've come across this twice now.
Sometimes using the following line of code:
[self.navigationController presentModalViewController:aViewController animated:YES];
displays the view, but the navigation bar is then hidden.
I can write:
[self.navigationController setNavigationBarHidden:NO];
to my hearts content, everywhere I can think of with no effect.
Has anyone ran into this?
Am I doing something silly?
No, I ran into this as well. The problem is that when you present a modal view controller with a UIViewController based class, it does not extend the calling navigation controller's nav bar onto the modal. The modal view covers the entire screen. What I ended up doing to solve the problem was to create a UINavigationController and push the UIViewController based class onto it, and then do presentModalViewController to the navigation controller's instance.
like:
UIViewController *vc = [[UIViewController alloc] init];
UINavigationController *cntrol = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentModalViewController:cntrol animated:YES];
[cntrol release];
That allowed me to have a nav bar at the top.
I am not sure if that will help in your particular case, the only other thing I would suggest is to replicate the behavior of the modal with a UIAnimation that stops 44px below the top of the phone. That would keep the original navigation bar visible.
#HeatMiser shows a great way to get around the "bug" surrounding the inability to display items on the nav bar. I'm not sure, however, if this is strictly a bug in Presentation, since modal operations ought to trump the underlying view's interface theme. Having the modal operation's theme mimic the underlying UI theme is fine, but wrapping the true modal view with a navigation view feels wrong to me (extra view object just to get a little more behavior).
Instead, the following worked for me and gives the same behavior as "New Message" does in the Mail program (on the iPhone).
In IB, place a UIToolBar at the top of the modal screen (mimicking the navigation bar) with "Cancel" and "Save" UIBarButtonItem's and a Flexible Space Bar Button Item in between to get the buttons to align left and right. Then, add a UILabel centered over the UIToolBar (The Font Helvetica, Bold, Size 18 appears to match the Navigation Bar Title). Connect the buttons to IBAction's on the modal's UIViewController, and you're done.
If there is a navigation controller active, then you should just use
[self.navigationController pushViewControllerAnimated:how];
to slide another view controller in, while giving yourself and the user into a consistent user interface complete with 'automatic' back button support.
Once a navigation controller is in use, presenting a modal view controller should only be done to enlarge the usable area on the screen. And then, you should really use a fancy animation to let the user know that you are stepping away from the "task" or "steps" that the navigation controller was embodying.
Maybe this is obvious, but once you're done with the modal view and want to dismiss it, you should do something like this in your modal vc:
[parentController dismissModalViewControllerAnimated:YES];
Where parentController is a reference to the vc from where you are presenting the modal view.
Related
On one of my views, when a button is pressed I call another view that is a SplitViewController. If this SplitViewController is called via one of these buttons I have special objects to add to the view. mostly just nav bar items, like a cancel button. This view can be accessed elsewhere and these items are not needed which is why there is the special condition.
However, when the user is done and i pop the ViewController back to the previous screen that was selected, the nav bar disappears on that screen. I am not setting it to hidden nor am I doing anything strange with the nav bar. Simply adding the SplitViewController then popping back.
Some code..
//declare the split screen VC
SplitScreenViewController *split = [[SplitScreenViewController alloc] init];
//set the flag that this VC is coming from a button, so we need the extra nav bar items
[split setIsFromButton:YES];
[self.navigationController pushViewController:split animated:YES];
now the call back is simply...
- (void)cancelSelectionBtnClicked
{
[self.navigationController popViewControllerAnimated:YES];
}
and when the view returns, the nav bar is gone.
any ideas?
edit it should be noted this exact same thing is done elsewhere the same way(as far as I can tell) and the nav bar is visible on return.
In your ViewController's viewWillAppear you can again make your navigationBar visible.
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:NO];
}
I have seen various strange navbar behavior in UISplitViewController's, and in a few cases it was because the controller was not set as the rootViewController of the window as opposed to inside a navigation controller like you have set up.
How do I navigate back to the previous page with a UITableViewController. I tried to show a navigation bar with navigation button at the top of the screen, but the navigation bar will not show. I know that you have to give the previous view a title but when I go to do that it does not show anything. Also, since it is a UITableViewController I am not able to drop a navigation bar and add a button to the main view. All I would like to do is display my lists and have the option to navigate back to the previous list with a single button in the upper left corner.
The problem you having with the NavigationController is that your tableViewController is not in the NavigationController hierarchy. Want you want to do this when adding the tableViewController:
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:yourTableViewController];
Then you can do this to add yourTableViewController:
[self.view addSubview:navigationController.view];
If you don't want the navigationBar to appear on the tableViewController just use:
self.navigationController.navigationBarHidden = YES;
in yourTableViewController viewWillAppear method.
When your going to add the view after the tableView you just use:
[self.navigationController pushViewController:someViewController animated:YES];
It's not enough to give the child view a title. You need to give the child view's navigation item a title before you present it. For example, in the parent view, before you push the the view to the navigation stack, do something like this...
[MyChildView.MyNavigationItem setTitle:#"A cool Title"];
For the navigation you are trying to achieve you should be using a UINavigationController. It already has the functionality you describe with the navigation bar and back button built into it.
To move to the next screen (which can be a UITableViewController) you use pushViewController:animated: and to move to the previous screen you use popViewControllerAnimated: (although the built in back button will do this for you).
I suggest reading the UINavigationController class documentation if you are not already familiar with it.
So before I push a new viewController onto the stack in a certain view, I set the navigationBar to hidden I notice that it disappears before the next screen gets pushed and the slide animation happens (because I need a UIToolbar at the top).
So question #1: is there a way to push a new view controller and setting the navigationbar to hidden, and not getting the hide animation until after the new view controller is on screen. it looks funny that the navigation bar hides then pushes the new view controller.
Once the new view controller is present, when I pop it off, I set the navigation bar back
[self.navigationController.navigationBar setHidden:NO];
But when it is popped, the navigationbar is not back any more. Is it because this navigationBar is for the current navigationController and not the new one that is being presented after the pop? (question #2)
Question 3: Realizing it isn't showing my navigationBar, in the viewController that gets presented after the pop, in its viewDidAppear, I added
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.navigationController.navigationBar setHidden:NO];
}
which shows the navigationBar, but the view size is incorrect since it seems like once the navigation bar was hidden, the rest of the view took up the empty space, and then the navigationBar is on top of the content. Is there anything I can do about this? Or am I approaching it incorrectly with push and pop?(question #3).
Thanks!
I was running into the very same problem (only in reverse: I was starting from a NavigationBar being hidden and pushing a view where I wanted the NavigationBar visible), and there's actually an extremely easy fix.
Simply replace your calls:
[self.navigationController.navigationBar setHidden:NO];
with
[[self navigationController] setNavigationBarHidden:NO animated:YES];
In my code, I call these statements in the - (void)viewWillAppear:(BOOL)animated methods of each respective View Controller.
I just tried this solution in the order you are using (visible, then hidden), and it seems to work just as well.
Interesting issue. You could try changing the hidden property in viewWillAppear and viewWillDisappear, but it seems like that might not give the desired results either.
Can you present the view controller modally instead of making the navigation bar disappear? If it's the last view controller on the stack, that would be possible. It might also make more sense to the user to see a view controller presented differently. This might indicate to the user that navigating away from this view controller is no longer done with the Back Button. It could be more reasonable than having the navigation bar just disappear.
If you still wanted the view controller to slide in from the right, I don't think it can be done with a modal view controller. But, you could do that by animating a view that fills the screen. (You just add the view with a frame that has origin.x equal to the width of the screen. Then, in the animation, you change origin.x to 0.0. Let me know if you need more detail on this.)
However, I would recommend presenting the view controller in a different manner from the way a view is generally presented by a navigation controller. Because, essentially, you are no longer letting the user navigate away from this view as he/she generally would from within a navigation controller. (So, my response to question #3 would be 'yes'.)
I'm writing an iPhone app that is based on a UINavigationController. I'm pulling data from a server that sometime returns bogus links. I open each link by pushing a webview viewcontroller. I want to be able to include some error handling. I know if the link is no good. So I want to be able to pop the webview view controller as soon as I know that my webview has encountered an error.
Currently, I've tried using the following code:
[self.navigationController popViewControllerAnimated:YES];
I then get a Navigation bar with nothing displayed in it, but if I click where the "back" button should be it operates appropriately. The title pops up when I click where the "back" button should be. The view where the viewcontrollers usually display there content is blank white too even though I'm popping back to a UITableViewController.
I've tried this as a workaround:
UINavigationController *nav = self.navigationController;
[self.navigationController popViewControllerAnimated:YES];
[nav.visibleViewController.view setNeedsDisplay];
I've checked the viewControllers array in the UINavigationController and it has the right viewcontrollers in it (ie it has removed the viewcontroller for the webview).
I also tried putting code in the viewWillAppear of the viewcontroller I'm popping back to, but the method is never getting called.
I'm looking for a way to force the UINavigationController to reload the same way that you can call reloadData on a UITableView.
Any help would be greatly appreciated.
I saw something like this on my app where I was using a navigation bar I added in Interface Builder on the root view of a navigation controller and then programmatically creating the nav bar and its subviews for the second view. When I would pop the second view to return to the first view I would hide the self.navigationcontroller bar which would show the white space underneath until the IB nav bar of the previous view appeared. To fix this I decided to stick with programmatically creating all my navbars which fixed the issue for me.
TL;DR - if you are using both IB and programmatically made navbars this can happen when popping views, stick with one or the other for all the navbars yo
I have an app which goes through a set of screens within a navigation controller, then there is a screen with a tab controller, which one of the contained views wants to display a modal view controller that should be displayed over the top of the whole app (not full screen though).
It's all working fine, but the modal window is partially covered at the top by the navigation controller. I've tried using self / self.tabBarController / self.navigationController / self.tabBarController.navigationController to call presentModalViewController but they either don't work or still display the modal window underneath.
I've been searching for an answer to this all day, everyone else seems to have problems when it DOES overlap, not when it doesn't.
Any ideas? Thanks. (code, screenshots & video below)
- (IBAction)add:(id)sender {
// create the view
AddAttainmentController *addScreen = [[AddAttainmentController alloc] init];
// pass in a selected pupil
[addScreen setPupils:[NSMutableArray arrayWithObject:pupil]];
// add the view to a navigation controller
UINavigationController *control = [[UINavigationController alloc] initWithRootViewController:addScreen];
// place the navigation controller on the screen
[self presentModalViewController:control animated:YES];
// release at the end
[control release];
[addScreen release];
}
Screenshots: http://cl.ly/032v2k0t0N1s1m3H0511 (you can see the navigation bar as the modal window slides in) http://cl.ly/1h0o453Y3Z051P3S1S37 (the navigation bar of the modal window is covered by the original)
Video: http://cl.ly/1e2J3o1q3V1l1j470m12
It sounds like you failed to consider some of the restrictions and assumptions around using Apple's view controller classes and are getting undefined and unexpected behavior as a result.
Tab bar controllers expect to always be at the root of your controller hierarchy. From the class reference:
When deploying a tab bar interface, you must install this view as the root of your window. Unlike other view controllers, a tab bar interface should never be installed as a child of another view controller
Additionally modal view controllers (and all view controllers for that matter) are assumed to fill their window.