iPhone: Показать модальный UITableViewController с панелью навигации

87

Я показываю модальное представление, которое является UITableViewControllerклассом. По какой-то причине он не отображает панель навигации, когда я показываю ее. Вот мой код:

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

Думал, по умолчанию показывается? Если это помогает, я вызываю это из другого класса, который также UITableViewControllerуправляется классом UINavigationController. Идеи?

Ник Хаббард
источник

Ответы:

146

Когда вы представляете контроллер модального представления, он не использует какие-либо существующие контроллеры навигации или панели навигации. Если все, что вам нужно, - это отобразить панель навигации, вам нужно добавить панель навигации в качестве части вашего модального представления и представить ее в том виде, в каком вы это делаете.

Если вы хотите представить контроллер модального представления с функцией навигации, вам необходимо вместо этого представить контроллер модальной навигации, содержащий контроллер детального представления, например:

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

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

Ваш модальный контроллер будет управлять своим собственным стеком навигации.

BoltClock
источник
Спасибо, я ценю объяснение, поэтому я знаю, что сделал не так.
Ник Хаббард
1
Если вы используете раскадровку, для этого не требуется никакого кодирования. Хорошее решение!
Jelle
36

Вот один из способов отображения панели навигации для тех, кто использует раскадровки, предложенный Apple Tutorial on Storyboard .

Поскольку контроллер модального представления не добавляется в стек навигации, он не получает панель навигации от контроллера навигации контроллера табличного представления. Чтобы дать контроллеру представления панель навигации при модальном представлении, встроите ее в собственный контроллер навигации.

  1. В представлении структуры выберите View Controller.
  2. Выделив контроллер представления, выберите «Редактор»> «Вставить в»> «Контроллер навигации».
Скотт
источник
Убедитесь, что вы добавили модальный переход к контроллеру навигации, а не к TableViewController
bickster
В случае страницы редактирования профиля пользователя Twitter. Это модально представленный UITableViewController с кнопками DONE и CANCEL вверху. Этот ответ не имеет семантического смысла в этой ситуации, потому что не происходит навигации.
Уильям Энтрикен,
17

В iOS 7 и вы просто хотите, чтобы панель навигации на контроллере модального представления отображала заголовок и несколько кнопок? Попробуйте эту магию в своем 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
источник
Шов - отличный способ делать вещи. но когда я тестирую его на Static UITableViewController, я больше не могу прокручивать табличное представление. есть идеи почему?
Thomas Besnehard
2
в настоящее время вам было бы лучше встроить его в контроллер навигации.
Malhal
Это хорошее решение, но одна небольшая проблема заключается в том, что при прокрутке заголовки ячеек отображаются поверх панели навигации.
Али
Решил, добавив [self.view bringSubviewToFront:self.navigationBar];в конце -(void)layoutNavigationBar.
Али
7

Хочу поделиться, как принятое решение можно использовать в проектах с раскадровкой:

Простой подход состоит в том, чтобы вставить пустой навигационный контроллер раскадровки перед VC, который должен быть представлен модально, чтобы отношения выглядели так:

(Presenter VC) -> представляет модально -> (контроллер навигации, имеющий контроллер, который должен быть представлен как его корень).

Мы пробовали этот подход какое-то время и заметили, что наши раскадровки «загрязняются» большим количеством таких промежуточных контроллеров навигации, когда каждый из них! из них используется исключительно для одного! представление некоторого другого контроллера, который мы хотим представить модально с панелью навигации.

Наше текущее решение - инкапсулировать код из принятого ответа на настраиваемый переход:

#import "ModalPresentationWithNavigationBarSegue.h"

@implementation ModalPresentationWithNavigationBarSegue

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

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

Имея этот сегмент в нашем проекте, мы больше не создаем промежуточные контроллеры навигации в наших раскадровках, мы просто используем этот ModalPresentationWithNavigationBarSegue как:

Ведущая ВК -> Ведущая ВК

Я надеюсь, что этот ответ будет полезен людям, которые любят избегать ненужного дублирования в раскадровках своих приложений.

Станислав Панкевич
источник
5

Если вам нужен только объект NavigationBar, вы можете добавить экземпляр UINavigationBarи назначить ему BarItems.

xhan
источник
Это зависит от ViewController: я думаю, вы не можете добавить UINavigationBar к UITableViewController, не так ли?
Тобиас
В IB перейдите в Editor -> Embed in Navigation Controller, и у вас будет панель навигации. Перетащите и добавьте к нему BarButtonItems.
AmitaiB
5

Я просто хотел добавить кое-что к тому, что сказал @Scott. Его ответ определенно является самым простым и наиболее приемлемым способом сделать это сейчас с помощью раскадровок, iOS 7 и 8 ... (а вскоре и 9).

Определенно добавление контроллера представления в раскадровку и его встраивание, как описано @Scott, - правильный путь.

Затем просто добавьте переход, перетащив элемент управления из исходного контроллера представления в целевой (тот, который вы хотите показать модально), выберите «Представить модально», когда появится небольшое представление с вариантами выбора типа перехода. Вероятно, неплохо было бы дать ему имя (в примере ниже я использую "presentMyModalViewController").

Одна вещь, которая мне была нужна, чего не хватало, - это случай @ Scott, когда вы действительно хотите передать некоторые данные в тот модально представленный контроллер представления, который встроен в контроллер навигации.

Если вы возьмете segue.destinationViewController, это будет UINavigationController, а не контроллер, который вы встроили в UINavigationController.

Итак, чтобы получить доступ к встроенному контроллеру представления внутри контроллера навигации, вот что я сделал:

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

Надеюсь это поможет!

Эван Стоун
источник