iPhone: Show modal UITableViewController with Navigation bar

IphoneObjective CIosUitableview

Iphone Problem Overview


I am showing a modal view which is a UITableViewController class. For some reason it won't show the navigation bar when I show it. Here is my code:

SettingsCreateAccount *detailViewController = [[SettingsCreateAccount alloc] initWithStyle:UITableViewStyleGrouped];
	detailViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
	detailViewController.navigationController.navigationBarHidden = NO;
	[self.navigationController presentModalViewController:detailViewController animated:YES];
	detailViewController = nil;
	[detailViewController release];

I thought it was shown by default? If it helps, I am calling this from another class that is also a UITableViewController managed by a UINavigationController. Ideas?

Iphone Solutions


Solution 1 - Iphone

When you present a modal view controller it does not use any existing navigation controllers or navigation bars. If all you want is to display a navigation bar, you need to add the navigation bar as a subview of your modal view and present it as you're doing.

If you want to present a modal view controller with navigation functionality, you need to present a modal navigation controller containing your detail view controller instead, like so:

SettingsCreateAccount *detailViewController = [[SettingsCreateAccount alloc] initWithStyle:UITableViewStyleGrouped];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
[detailViewController release];

navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:navController animated:YES];
[navController release];

Your modal controller will manage its own navigation stack.

Solution 2 - Iphone

Here is one way to display navigation bar for those who are using storyboards, suggested by Apple's Tutorial on Storyboard.

Because a modal view controller doesn’t get added to the navigation stack, it doesn’t get a navigation bar from the table view controller’s navigation controller. To give the view controller a navigation bar when presented modally, embed it in its own navigation controller.

  1. In the outline view, select View Controller.
  2. With the view controller selected, choose Editor > Embed In > Navigation Controller.

Solution 3 - Iphone

On iOS 7 and you just want a navigation bar on your modal view controller to show a title and some buttons? Try this magic in your UITableViewController:

// in the .h
@property (strong) UINavigationBar* navigationBar;

//in the .m
- (void)viewDidLoad {
    [super viewDidLoad];

    self.navigationItem.title = @"Awesome";
    self.navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectZero];
    [self.view addSubview:_navigationBar];
    [self.navigationBar pushNavigationItem:self.navigationItem animated:NO];
}

-(void)layoutNavigationBar{
    self.navigationBar.frame = CGRectMake(0, self.tableView.contentOffset.y, self.tableView.frame.size.width, self.topLayoutGuide.length + 44);
    self.tableView.contentInset = UIEdgeInsetsMake(self.navigationBar.frame.size.height, 0, 0, 0);
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    //no need to call super
    [self layoutNavigationBar];
}

-(void)viewDidLayoutSubviews{
    [super viewDidLayoutSubviews];
    [self layoutNavigationBar];
}

Solution 4 - Iphone

I want to share how the accepted solution can be used in projects with storyboards:

The simple approach is to put in a storyboard blank navigation controller before the VC which is to be presented modally, so the relations look like:

> (Presenter VC) -> presents modally -> (navigation controller having a controller to be presented as its root).

We've tried this approach for a while and noticed that our storyboards become "polluted" by a large number of such intermediate navigation controllers when each! of them is used exclusively for one! presentation of some other controller, that we want to be presented modally with navigation bar.

Our current solution is to encapsulate the code from accepted answer to a custom segue:

#import "ModalPresentationWithNavigationBarSegue.h"

@implementation ModalPresentationWithNavigationBarSegue

- (void)perform {
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.destinationViewController];

    [self.sourceViewController presentViewController:navigationController animated:YES completion:nil];
}
@end

Having this segue in our project we do not create intermediate navigation controllers in our storyboards anymore, we just use this ModalPresentationWithNavigationBarSegue like:

> Presenter VC --> Presentee VC

I hope that this answer will be helpful to people who like to avoid unnecessary duplication in their apps storyboards.

Solution 5 - Iphone

I just wanted to add something to what @Scott said. His answer is definitely the easiest and most accepted way of doing it now with Storyboards, iOS 7 and 8... (and soon, 9).

Definitely adding a view controller to the Storyboard and Embedding it as described by @Scott is the right way to go.

Then, just add the segue by control-dragging from the source view controller to the target (the one you want to show modally), select "Present Modally" when the little view appears with the choices for the type of segue. Probably good to give it a name too (in the example below I use "presentMyModalViewController").

One thing that I needed that was missing is @Scott's case is when you want to actually pass on some data to that modally-presented view controller that is embedded in the navigation controller.

If you grab the segue.destinationViewController, it will be a UINavigationController, not the controller you embedded in the UINavigationController.

So, to get at the embedded view controller inside the navigation controller, here's what I did:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"presentMyModalViewController"]) {
        // This could be collapsed, but it's a little easier to see
        // what's going on written out this way.

        // First get the destination view controller, which will be a UINavigationController
        UINavigationController *nvc = (UINavigationController *)segue.destinationViewController;

        // To get the view controller we're interested in, grab the navigation controller's "topViewController" property
        MyModalViewController *vc = (EmailReceiptViewController *)[nvc topViewController];

        // Now that we have the reference to our view controller, we can set its properties here:
        vc.myAwesomeProperty = @"awesome!";
    }
}

Hope this helps!

Solution 6 - Iphone

If you only need a NavigationBar, you can add an instance of UINavigationBar and assign BarItems to it.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNic HubbardView Question on Stackoverflow
Solution 1 - IphoneBoltClockView Answer on Stackoverflow
Solution 2 - IphoneScottView Answer on Stackoverflow
Solution 3 - IphonemalhalView Answer on Stackoverflow
Solution 4 - IphoneStanislav PankevichView Answer on Stackoverflow
Solution 5 - IphoneEvan K. StoneView Answer on Stackoverflow
Solution 6 - IphonexhanView Answer on Stackoverflow