IPhone: 用导航栏显示模态 UITableViewController

我显示了一个模态视图,这是一个 UITableViewController类。由于某种原因,它不会显示导航栏时,我显示它。这是我的代码:

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

我以为是默认显示的?如果有帮助的话,我将从另一个类调用它,该类也是由 UINavigationController管理的 UITableViewController。有什么想法吗?

55255 次浏览

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.

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

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];
}

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.

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.

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!