iPhone: Mostrar UITableViewController modal com barra de navegação

87

Estou mostrando uma visão modal que é uma UITableViewControllerclasse. Por algum motivo, ele não mostrará a barra de navegação quando eu mostro. Aqui está o meu 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];

Achei que fosse mostrado por padrão? Se ajudar, estou ligando de outra classe que também é UITableViewControllergerenciada por a UINavigationController. Ideias?

Nic Hubbard
fonte

Respostas:

146

Quando você apresenta um controlador de visualização modal, ele não usa nenhum controlador de navegação ou barras de navegação existentes. Se tudo o que você deseja é exibir uma barra de navegação, você precisa adicionar a barra de navegação como uma subvisão de sua visão modal e apresentá-la enquanto está fazendo.

Se você deseja apresentar um controlador de visualização modal com funcionalidade de navegação, é necessário apresentar um controlador de navegação modal contendo seu controlador de visualização de detalhes, como:

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

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

Seu controlador modal gerenciará sua própria pilha de navegação.

BoltClock
fonte
Obrigado, agradeço a explicação, então sei o que fiz de errado.
Nic Hubbard
1
Se você usa um storyboard, não há nenhuma codificação envolvida para fazer isso. Boa solução!
Jelle
36

Esta é uma maneira de exibir a barra de navegação para quem está usando storyboards, sugerida pelo Tutorial da Apple sobre Storyboard .

Como um controlador de visualização modal não é adicionado à pilha de navegação, ele não obtém uma barra de navegação do controlador de navegação do controlador de visualização de tabela. Para dar ao controlador de visualização uma barra de navegação quando apresentada modalmente, incorpore-a em seu próprio controlador de navegação.

  1. Na vista de esboço, selecione View Controller.
  2. Com o controlador de visualização selecionado, escolha Editor> Embed In> Controlador de navegação.
Scott
fonte
Certifique-se de adicionar a segue modal ao Controlador de navegação e não ao TableViewController
bickster
Na situação da página de edição de perfil de usuário do Twitter. Este é um UITableViewController apresentado de forma modal e tem os botões DONE e CANCEL na parte superior. Essa resposta não faz sentido semanticamente nessa situação, porque não há navegação acontecendo.
William Entriken
17

No iOS 7 e você deseja apenas uma barra de navegação em seu controlador de visualização modal para mostrar um título e alguns botões? Experimente esta mágica em seu 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
fonte
Parece ser uma ótima maneira de fazer as coisas. mas quando estou fazendo o teste em um UITableViewController estático, não consigo mais rolar o tableview. alguma ideia do porquê?
Thomas Besnehard
2
hoje em dia, seria melhor incorporá-lo a um controlador de navegação.
malhal
Essa é uma boa solução, mas um pequeno problema é que, quando você rola, os títulos dos cabeçalhos das células aparecem no topo da barra de navegação.
Ali
Eu resolvi isso adicionando [self.view bringSubviewToFront:self.navigationBar];no final de -(void)layoutNavigationBar.
Ali
7

Quero compartilhar como a solução aceita pode ser usada em projetos com storyboards:

A abordagem simples é colocar um controlador de navegação em branco do storyboard antes do VC, que deve ser apresentado modalmente, para que as relações sejam semelhantes a:

(Presenter VC) -> apresenta modalmente -> (controlador de navegação tendo um controlador a ser apresentado como sua raiz).

Tentamos essa abordagem por um tempo e percebemos que nossos storyboards ficam "poluídos" por um grande número desses controladores de navegação intermediários quando cada um! deles é usado exclusivamente para um! apresentação de algum outro controlador, que queremos apresentar modalmente com barra de navegação.

Nossa solução atual é encapsular o código da resposta aceita para uma transição personalizada:

#import "ModalPresentationWithNavigationBarSegue.h"

@implementation ModalPresentationWithNavigationBarSegue

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

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

Tendo este segue em nosso projeto, não criamos mais controladores de navegação intermediários em nossos storyboards, apenas usamos este ModalPresentationWithNavigationBarSegue como:

Apresentador VC -> Presentee VC

Espero que esta resposta seja útil para pessoas que gostam de evitar duplicações desnecessárias nos storyboards de seus aplicativos.

Stanislav Pankevich
fonte
5

Se você só precisa de um NavigationBar, pode adicionar uma instância de UINavigationBare atribuir BarItems a ele.

xhan
fonte
Isso depende do ViewController: acho que você não pode adicionar um UINavigationBar a um UITableViewController, pode?
Tobias
No IB, vá para Editor -> Embed in Navigation Controller e você terá uma barra de navegação. Arraste e adicione BarButtonItems a isso.
AmitaiB
5

Eu só queria acrescentar algo ao que @Scott disse. Sua resposta é definitivamente a maneira mais fácil e aceita de fazer isso agora com Storyboards, iOS 7 e 8 ... (e em breve, 9).

Definitivamente, adicionar um controlador de visualização ao Storyboard e incorporá-lo conforme descrito por @Scott é o caminho certo a seguir.

Então, basta adicionar a segue arrastando e controlando do controlador de visualização de origem para o destino (aquele que você deseja mostrar modalmente), selecione "Apresentar modalmente" quando a pequena visualização aparecer com as opções para o tipo de segue. Provavelmente bom dar um nome a ele também (no exemplo abaixo eu uso "presentMyModalViewController").

Uma coisa que eu precisava que estava faltando é o caso de @ Scott é quando você deseja realmente passar alguns dados para aquele controlador de visualização apresentado modalmente que está embutido no controlador de navegação.

Se você pegar o segue.destinationViewController, ele será um UINavigationController, não o controlador que você incorporou ao UINavigationController.

Então, para chegar ao controlador de visualização incorporado dentro do controlador de navegação, aqui está o que eu fiz:

- (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 isto ajude!

Evan Stone
fonte