iPhone: Mostrar UITableViewController modal con barra de navegación

87

Estoy mostrando una vista modal que es una UITableViewControllerclase. Por alguna razón, no mostrará la barra de navegación cuando la muestre. Aquí está mi código:

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

Pensé que se mostraba por defecto. Si ayuda, lo estoy llamando desde otra clase que también es UITableViewControlleradministrada por un UINavigationController. Ideas?

Nic Hubbard
fuente

Respuestas:

146

Cuando presenta un controlador de vista modal, no utiliza ningún controlador de navegación ni barras de navegación existentes. Si todo lo que desea es mostrar una barra de navegación, debe agregar la barra de navegación como una subvista de su vista modal y presentarla como lo está haciendo.

Si desea presentar un controlador de vista modal con funcionalidad de navegación, debe presentar un controlador de navegación modal que contenga su controlador de vista de detalle en su lugar, así:

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

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

Su controlador modal administrará su propia pila de navegación.

BoltClock
fuente
Gracias, agradezco la explicación para saber qué había hecho mal.
Nic Hubbard
1
Si usa un guión gráfico, no hay ninguna codificación involucrada para lograr esto. ¡Buena solución!
Jelle
36

Aquí hay una forma de mostrar la barra de navegación para aquellos que usan guiones gráficos, sugerida por el Tutorial de Apple en Storyboard .

Debido a que un controlador de vista modal no se agrega a la pila de navegación, no obtiene una barra de navegación del controlador de navegación del controlador de vista de tabla. Para darle al controlador de vista una barra de navegación cuando se presenta de forma modal, incruste en su propio controlador de navegación.

  1. En la vista de esquema, seleccione Ver controlador.
  2. Con el controlador de vista seleccionado, elija Editor> Insertar en> Controlador de navegación.
Scott
fuente
Asegúrese de agregar el segue modal al controlador de navegación y no al TableViewController
bickster
En la situación de la página de edición de perfil de usuario de Twitter. Este es un UITableViewController presentado modalmente y tiene botones DONE y CANCEL en la parte superior. Esta respuesta no tiene sentido semánticamente en esa situación porque no hay navegación.
William Entriken
17

¿En iOS 7 y solo desea una barra de navegación en su controlador de vista modal para mostrar un título y algunos botones? Prueba esta magia en tu 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
fuente
Parece ser una excelente manera de hacer las cosas. pero cuando lo estoy probando en un UITableViewController estático, ya no puedo desplazarme por la vista de tabla. alguna idea de por qué?
Thomas Besnehard
2
hoy en día sería mejor incrustarlo en un controlador de navegación.
Malhal
Esa es una buena solución, pero un pequeño problema es que cuando se desplaza, los títulos del encabezado de la celda se muestran en la parte superior de la barra de navegación.
Ali
Lo resolví agregando [self.view bringSubviewToFront:self.navigationBar];al final de -(void)layoutNavigationBar.
Ali
7

Quiero compartir cómo se puede utilizar la solución aceptada en proyectos con guiones gráficos:

El enfoque simple es colocar un controlador de navegación en blanco del guión gráfico antes del VC que se presentará modalmente, para que las relaciones se vean como:

(Presenter VC) -> presenta modalmente -> (controlador de navegación que tiene un controlador que se presentará como su raíz).

Hemos probado este enfoque por un tiempo y notamos que nuestros guiones gráficos se "contaminan" por una gran cantidad de estos controladores de navegación intermedios cuando cada uno! de ellos se utiliza exclusivamente para uno! presentación de algún otro controlador, que queremos que se presente modalmente con barra de navegación.

Nuestra solución actual es encapsular el código de la respuesta aceptada a un segue personalizado:

#import "ModalPresentationWithNavigationBarSegue.h"

@implementation ModalPresentationWithNavigationBarSegue

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

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

Teniendo esta segue en nuestro proyecto, ya no creamos controladores de navegación intermedios en nuestros guiones gráficos, solo usamos este ModalPresentationWithNavigationBarSegue como:

Presentador VC -> Presentador VC

Espero que esta respuesta sea útil para las personas a las que les gusta evitar la duplicación innecesaria en los guiones gráficos de sus aplicaciones.

Stanislav Pankevich
fuente
5

Si solo necesita un NavigationBar, puede agregar una instancia UINavigationBary asignarle BarItems.

xhan
fuente
Eso depende del ViewController: creo que no puede agregar un UINavigationBar a un UITableViewController, ¿verdad?
Tobias
En IB, vaya a Editor -> Insertar en controlador de navegación, y tendrá una barra de navegación. Arrastre y agregue BarButtonItems a eso.
AmitaiB
5

Solo quería agregar algo a lo que dijo @Scott. Su respuesta es definitivamente la forma más fácil y aceptada de hacerlo ahora con Storyboards, iOS 7 y 8 ... (y pronto, 9).

Definitivamente, agregar un controlador de vista al Storyboard e incrustarlo como lo describe @Scott es el camino correcto.

Luego, simplemente agregue el segue arrastrando el control desde el controlador de la vista de origen al destino (el que desea mostrar modalmente), seleccione "Presentar modalmente" cuando aparezca la pequeña vista con las opciones para el tipo de segue. Probablemente sea bueno darle un nombre también (en el siguiente ejemplo utilizo "presentMyModalViewController").

Una cosa que necesitaba que faltaba es el caso de @ Scott es cuando realmente desea pasar algunos datos a ese controlador de vista presentado modalmente que está incrustado en el controlador de navegación.

Si toma el segue.destinationViewController, será un UINavigationController, no el controlador que incrustó en UINavigationController.

Entonces, para acceder al controlador de vista integrado dentro del controlador de navegación, esto es lo que hice:

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

¡Espero que esto ayude!

Evan Stone
fuente