iPhone: affichez UITableViewController modal avec la barre de navigation

87

Je montre une vue modale qui est une UITableViewControllerclasse. Pour une raison quelconque, il n'affiche pas la barre de navigation lorsque je le montre. Voici mon code:

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

Je pensais qu'il était affiché par défaut? Si cela aide, j'appelle cela depuis une autre classe qui est également UITableViewControllergérée par un UINavigationController. Des idées?

Nic Hubbard
la source

Réponses:

146

Lorsque vous présentez un contrôleur de vue modale, il n'utilise aucun contrôleur de navigation ou barre de navigation existants. Si tout ce que vous voulez est d'afficher une barre de navigation, vous devez ajouter la barre de navigation en tant que sous-vue de votre vue modale et la présenter comme vous le faites.

Si vous souhaitez présenter un contrôleur de vue modale avec des fonctionnalités de navigation, vous devez plutôt présenter un contrôleur de navigation modal contenant votre contrôleur de vue détaillée, comme ceci:

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

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

Votre contrôleur modal gérera sa propre pile de navigation.

BoltClock
la source
Merci, j'apprécie l'explication donc je sais ce que j'avais fait de mal.
Nic Hubbard
1
Si vous utilisez un storyboard, il n'y a aucun codage impliqué pour accomplir cela. Bonne solution!
Jelle
36

Voici une façon d'afficher la barre de navigation pour ceux qui utilisent des storyboards, suggérée par le didacticiel d' Apple sur Storyboard .

Étant donné qu'un contrôleur de vue modale n'est pas ajouté à la pile de navigation, il n'obtient pas de barre de navigation du contrôleur de navigation du contrôleur de vue de table. Pour donner au contrôleur de vue une barre de navigation lorsqu'elle est présentée de manière modale, intégrez-la dans son propre contrôleur de navigation.

  1. Dans la vue d'ensemble, sélectionnez Afficher le contrôleur.
  2. Avec le contrôleur de vue sélectionné, choisissez Editeur> Incorporer dans> Contrôleur de navigation.
Scott
la source
Assurez-vous d'ajouter la séquence modale au contrôleur de navigation et non au TableViewController
bickster
Dans le cas de la page de modification du profil utilisateur de Twitter. Ceci est un UITableViewController présenté modalement et il a des boutons DONE et CANCEL en haut. Cette réponse n'a aucun sens sémantiquement dans cette situation car il n'y a pas de navigation en cours.
William Entriken
17

Sur iOS 7 et vous voulez juste une barre de navigation sur votre contrôleur de vue modale pour afficher un titre et quelques boutons? Essayez cette magie dans votre 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];
}
malhal
la source
Seam est un excellent moyen de faire les choses. mais quand je le teste sur un UITableViewController statique, je ne suis plus en mesure de faire défiler la vue du tableau. une idée pourquoi?
Thomas Besnehard
2
de nos jours, vous feriez mieux de l'intégrer dans un contrôleur de navigation.
malhal
C'est une bonne solution, mais un petit problème est que lorsque vous faites défiler les titres des en-têtes de cellule, ils s'affichent en haut de la barre de navigation.
Ali
Je l'ai résolu en ajoutant [self.view bringSubviewToFront:self.navigationBar];à la fin de -(void)layoutNavigationBar.
Ali
7

Je souhaite partager comment la solution acceptée peut être utilisée dans des projets avec des storyboards:

L'approche simple consiste à insérer un contrôleur de navigation vierge de storyboard avant le VC qui doit être présenté de manière modale, de sorte que les relations ressemblent à:

(Presenter VC) -> présente modalement -> (contrôleur de navigation ayant un contrôleur à présenter en tant que racine).

Nous avons essayé cette approche pendant un certain temps et avons remarqué que nos storyboards deviennent "pollués" par un grand nombre de ces contrôleurs de navigation intermédiaires lorsque chacun! d'entre eux est utilisé exclusivement pour un! présentation d'un autre contrôleur, que nous souhaitons présenter modalement avec barre de navigation.

Notre solution actuelle consiste à encapsuler le code de la réponse acceptée à une séquence personnalisée:

#import "ModalPresentationWithNavigationBarSegue.h"

@implementation ModalPresentationWithNavigationBarSegue

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

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

Ayant cette séquence dans notre projet, nous ne créons plus de contrôleurs de navigation intermédiaires dans nos storyboards, nous utilisons simplement ce ModalPresentationWithNavigationBarSegue comme:

Présentateur VC -> Présentateur VC

J'espère que cette réponse sera utile aux personnes qui aiment éviter la duplication inutile dans leurs storyboards d'applications.

Stanislav Pankevich
la source
5

Si vous n'avez besoin que d'un NavigationBar, vous pouvez ajouter une instance de UINavigationBaret lui attribuer des BarItems.

xhan
la source
Cela dépend du ViewController: je pense que vous ne pouvez pas ajouter un UINavigationBar à un UITableViewController, n'est-ce pas?
Tobias
Dans IB, allez dans Editeur -> Incorporer dans le contrôleur de navigation, et vous aurez une barre de navigation. Faites glisser et ajoutez BarButtonItems à cela.
AmitaiB du
5

Je voulais juste ajouter quelque chose à ce que @Scott a dit. Sa réponse est certainement la manière la plus simple et la plus acceptée de le faire maintenant avec Storyboards, iOS 7 et 8 ... (et bientôt, 9).

Ajouter définitivement un contrôleur de vue au Storyboard et l'intégrer comme décrit par @Scott est la bonne voie à suivre.

Ensuite, ajoutez simplement le segue en faisant glisser le contrôle depuis le contrôleur de vue source vers la cible (celui que vous souhaitez afficher modalement), sélectionnez "Présenter modalement" lorsque la petite vue apparaît avec les choix pour le type de segue. Probablement bon de lui donner un nom aussi (dans l'exemple ci-dessous, j'utilise "presentMyModalViewController").

Une chose dont j'avais besoin et qui manquait est le cas de @ Scott, c'est lorsque vous voulez réellement transmettre certaines données à ce contrôleur de vue présenté de manière modale qui est intégré dans le contrôleur de navigation.

Si vous récupérez le segue.destinationViewController, ce sera un UINavigationController, pas le contrôleur que vous avez intégré dans le UINavigationController.

Donc, pour accéder au contrôleur de vue intégré à l'intérieur du contrôleur de navigation, voici ce que j'ai fait:

- (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!";
    }
}

J'espère que cela t'aides!

Pierre Evan
la source