iPhone: Pokaż modalny kontroler UITableViewController z paskiem nawigacji

87

Pokazuję widok modalny, który jest UITableViewControllerklasą. Z jakiegoś powodu nie wyświetla paska nawigacji, gdy go pokazuję. Oto mój kod:

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

Myślałem, że jest wyświetlany domyślnie? Jeśli to pomoże, wzywam to z innej klasy, która jest również UITableViewControllerzarządzana przez UINavigationController. Pomysły?

Nic Hubbard
źródło

Odpowiedzi:

146

Kiedy przedstawiasz kontroler widoku modalnego, nie używa on żadnych istniejących kontrolerów nawigacji ani pasków nawigacji. Jeśli chcesz tylko wyświetlić pasek nawigacji, musisz dodać pasek nawigacji jako podwidok swojego widoku modalnego i prezentować go tak, jak robisz.

Jeśli chcesz przedstawić kontroler widoku modalnego z funkcją nawigacji, musisz zamiast tego przedstawić kontroler nawigacji modalnej zawierający kontroler widoku szczegółów, na przykład:

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

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

Twój kontroler modalny będzie zarządzał własnym stosem nawigacji.

BoltClock
źródło
Dziękuję, doceniam wyjaśnienie, więc wiem, co zrobiłem źle.
Nic Hubbard,
1
Jeśli używasz storyboardu, nie ma w tym żadnego kodowania, aby to osiągnąć. Dobre rozwiązanie!
Jelle
36

Oto jeden ze sposobów wyświetlania paska nawigacji dla tych, którzy używają scenorysów, sugerowany przez samouczek Apple dotyczący Storyboard .

Ponieważ kontroler widoku modalnego nie jest dodawany do stosu nawigacji, nie otrzymuje paska nawigacji z kontrolera nawigacji kontrolera widoku tabeli. Aby nadać kontrolerowi widoku pasek nawigacji, gdy jest prezentowany modalnie, umieść go we własnym kontrolerze nawigacji.

  1. W widoku konspektu wybierz opcję Wyświetl kontroler.
  2. Po zaznaczeniu kontrolera widoku wybierz polecenie Edytor> Osadź w> Kontroler nawigacji.
Scott
źródło
Upewnij się, że dodajesz modalną segue do kontrolera nawigacji, a nie TableViewController
Bickster
W sytuacji edytowania strony profilu użytkownika Twittera. Jest to UITableViewController prezentowany modalnie i ma na górze przyciski DONE i CANCEL. Ta odpowiedź nie ma sensu semantycznego w tej sytuacji, ponieważ nie ma żadnej nawigacji.
William Entriken
17

W systemie iOS 7 i chcesz, aby pasek nawigacyjny na kontrolerze widoku modalnego wyświetlał tytuł i niektóre przyciski? Wypróbuj tę magię w swoim 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
źródło
Wydają się być świetnym sposobem na robienie rzeczy. ale kiedy próbuję go na Static UITableViewController, nie mogę już przewijać widoku tabeli. jakiś pomysł, dlaczego?
Thomas Besnehard
2
obecnie lepiej byłoby osadzić go w kontrolerze nawigacyjnym.
malhal
To fajne rozwiązanie, ale jeden mały problem polega na tym, że podczas przewijania tytułów nagłówków komórek wyświetlają się u góry paska nawigacyjnego.
Ali
Rozwiązałem to, dodając [self.view bringSubviewToFront:self.navigationBar];na końcu -(void)layoutNavigationBar.
Ali
7

Chcę się podzielić tym, jak przyjęte rozwiązanie można wykorzystać w projektach z storyboardami:

Prostym podejściem jest umieszczenie pustego kontrolera nawigacyjnego storyboardu przed VC, który ma być prezentowany modalnie, więc relacje wyglądają następująco:

(Presenter VC) -> prezentuje modalnie -> (kontroler nawigacyjny z kontrolerem, który ma być prezentowany jako jego root).

Próbowaliśmy tego podejścia przez jakiś czas i zauważyliśmy, że nasze storyboardy zostały „zanieczyszczone” przez dużą liczbę takich pośrednich kontrolerów nawigacji, kiedy każdy z nich! z nich jest używany wyłącznie do jednego! prezentacja innego kontrolera, który chcemy modalnie prezentować z paskiem nawigacji.

Nasze obecne rozwiązanie polega na hermetyzowaniu kodu z zaakceptowanej odpowiedzi do niestandardowego przejścia:

#import "ModalPresentationWithNavigationBarSegue.h"

@implementation ModalPresentationWithNavigationBarSegue

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

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

Mając ten fragment w naszym projekcie, nie tworzymy już pośrednich kontrolerów nawigacji w naszych scenorysach, po prostu używamy tego ModalPresentationWithNavigationBarSegue jak:

Presenter VC -> Presentee VC

Mam nadzieję, że ta odpowiedź będzie pomocna dla osób, które lubią unikać niepotrzebnego powielania scenorysów swoich aplikacji.

Stanislav Pankevich
źródło
5

Jeśli potrzebujesz tylko NavigationBar, możesz dodać wystąpienie UINavigationBari przypisać do niego BarItems.

xhan
źródło
To zależy od ViewController: myślę, że nie możesz dodać UINavigationBar do UITableViewController, prawda?
Tobias
W IB przejdź do Editor -> Embed in Navigation Controller, a będziesz mieć pasek nawigacji. Przeciągnij i dodaj do tego BarButtonItems.
AmitaiB
5

Chciałem tylko dodać coś do tego, co powiedział @Scott. Jego odpowiedź jest zdecydowanie najłatwiejszym i najbardziej akceptowanym sposobem na zrobienie tego teraz z Storyboards, iOS 7 i 8 ... (a wkrótce 9).

Zdecydowanie dodanie kontrolera widoku do Storyboardu i osadzenie go zgodnie z opisem @Scott jest właściwą drogą.

Następnie po prostu dodaj płynność, przeciągając kontrolką z kontrolera widoku źródła do celu (tego, który chcesz wyświetlić modalnie), wybierz „Prezentuj modalnie”, gdy pojawi się mały widok z opcjami dla typu płynności. Prawdopodobnie dobrze jest też nadać mu nazwę (w poniższym przykładzie używam "presentMyModalViewController").

Jedyną rzeczą, której potrzebowałem, a której brakowało, jest przypadek @ Scotta, gdy chcesz faktycznie przekazać niektóre dane do tego modalnie prezentowanego kontrolera widoku, który jest osadzony w kontrolerze nawigacji.

Jeśli pobierzesz segue.destinationViewController, będzie to UINavigationController, a nie kontroler osadzony w UINavigationController.

Tak więc, aby uzyskać dostęp do wbudowanego kontrolera widoku wewnątrz kontrolera nawigacji, oto co zrobiłem:

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

Mam nadzieję że to pomoże!

Evan Stone
źródło