UISplitViewController - несколько подробных представлений с UINavigationController

Я конвертирую приложение для iPhone в универсальное приложение, и в основном было просто преобразовать вложенные таблицы в структуру UISplitViewController, но у меня осталась проблема при работе на iPad, которая доставляет мне головную боль.

Для универсальной совместимости приложений «главное» представление содержит UINavigationController, который используется для навигации по серии TableView, каждый из которых отображает меню. Это нормально работает.

В конце концов, пользователь переходит к контенту, который отображается в подробном представлении. Каждая «цепочка» подробных представлений содержится в UINavigationController, так как некоторые представления могут выполнять детализацию для отображения карт и т. Д. Идея состоит в том, что кнопка всплывающего окна будет находиться на корневом уровне подробного представления. Вероятно, важно отметить, что подробные представления создаются с нуля каждый раз, когда выбирается эта строка.

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

При работе в ландшафтном режиме я могу выбирать разные строки в главном представлении, и подробные представления хорошо переключаются - все отлично работает. Это замечательно.

В портретном режиме все работает не так хорошо ... кнопка всплывающего окна отображается правильно в текущем выбранном подробном представлении при повороте в портретный режим, но затем исчезает, когда выбрана строка (то есть она почему-то неправильно добавляется к новому NavBar выбранного представления).

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

Поскольку подробные представления не создаются до тех пор, пока не будет выбрана строка, мне было интересно, был ли это случай, когда UINavigationBar не создавался во время вызова showRootPopoverButtonItem (на основе примера кода Apple). Эта теория подтверждается тем фактом, что кнопка всплывающего окна появляется, если я поворачиваюсь в альбомную ориентацию и обратно (как упоминалось выше) с тем же выбранным представлением.

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

// Configure the new view controller's popover button (after the view has been displayed and its toolbar/navigation bar has been created).

Итак, я попытался снова вызвать метод showRootPopoverButton в viewWillAppear (к тому времени должен существовать UINavigationBar), но это также не привело к появлению кнопки всплывающего окна.

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

Спасибо, что дочитали до этого места, соответствующий код ниже.

В главном представлении представлены селекторы UISplitViewControllerDelegate,

- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc
{

    // Keep references to the popover controller and the popover button, and tell the detail view controller to show the button.
    barButtonItem.title = @"Root View Controller";
    self.popoverController = pc;
    self.rootPopoverButtonItem = barButtonItem;
    //UIViewController <SubstitutableDetailViewController> *detailViewController = [self.splitViewController.viewControllers objectAtIndex:1];

    // ^ Apple's example, commented out, my equivalent code to obtain
    // active detail navigation controller below,

    UINavigationController *detailNavController = [self.splitViewController.viewControllers objectAtIndex:1];
    UIViewController *detailViewController = detailNavController.visibleViewController;

    [detailViewController showRootPopoverButtonItem:rootPopoverButtonItem];
}


- (void)splitViewController:(UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
     // Nil out references to the popover controller and the popover button, and tell the detail view controller to hide the button.
     UINavigationController *detailNavController = [self.splitViewController.viewControllers objectAtIndex:1];
     UIViewController *detailViewController = detailNavController.visibleViewController;
     [detailViewController invalidateRootPopoverButtonItem:rootPopoverButtonItem];
     self.popoverController = nil;
     self.rootPopoverButtonItem = nil;
}

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

if (rootPopoverButtonItem != nil)
{
    NSLog (@"show popover button");
    [newDetailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}

В подробном представлении

- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
{
    NSLog (@"detailViewController (view: %p, button: %p, nav: %p): showRootPopoverButton", self, barButtonItem, self.navigationItem);

    barButtonItem.title = self.navigationItem.title;

    [self.navigationItem setLeftBarButtonItem:barButtonItem animated:NO];

    popoverButton = barButtonItem;
}


- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem
{    
    NSLog (@"detailViewController (%p): invalidateRootPopoverButton", self);

    // Called when the view is shown again in the split view, invalidating the button and popover controller.
    [self.navigationItem setLeftBarButtonItem:nil animated:NO];

    popoverButton = nil;
}

person Snips    schedule 14.02.2012    source источник


Ответы (1)


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

  1. visibleViewController может быть нулевым, если вы только что создали detailNavController. Даже если вы установите его root, «видимого» контроллера представления нет, поскольку он еще не отображался. Вы можете попробовать использовать topViewController

  2. Я не уверен, что вы создаете новый detailNavController каждый раз, когда пользователь что-то выбирает в мастере, но если да, вам нужно снова передать rootPopoverButtonItem в detailViewController, потому что - (void)splitViewController: willHideViewController: withBarButtonItem: forPopoverController: вызывается автоматически только при изменении ориентации.

person gdix    schedule 17.02.2012
comment
Спасибо! Часть 1. вашего ответа направила меня на верный путь. Мне потребовалось слишком много времени, чтобы понять это, я ценю вашу помощь. - person Snips; 18.02.2012
comment
Спасибо! Чтобы решить эту проблему, я сохранил ссылку на rootPopoverButtonItem в моем одноэлементном классе - похоже, работает хорошо. - person RyanG; 13.12.2012