Подтвердить что ты не робот

UINavigationController внутри UITabBarController внутри UISplitViewController, представленный модально на iPhone

У меня есть UISplitViewController, который содержит UITabBarController как главный вид. Этот UITabBarController содержит UINavigationController. Детальный вид содержит также UINavigationController.

Storyboard

На iPad это работает так, как ожидалось. Сегмент show segue представляет изображение в навигационном контроллере на подробном представлении.

На iPhone, с другой стороны, я ожидал, что фрагмент show detail segue подталкивает подробный вид в стек навигационного контроллера основного вида. Но на самом деле оно представлено по образцу мастера.

При удалении UITabBarController из раскадровки и использовании UINavigationController непосредственно в главном представлении это работает.

Есть ли у кого-нибудь идея, как я мог бы представить подробный вид на стек главного мастера UINavigationController на iPhone?

4b9b3361

Ответ 1

Я выяснил, как разместить деталь на главном UINavigationController, вместо того, чтобы представлять его по тексту над UITabBarController.

Использование метода UISplitViewControllerDelegate

- splitViewController:showDetailViewController:sender:

Если UISplitViewController свернут, получите контроллер навигации мастеров и нажмите подробный вид на этот контроллер навигации:

- (BOOL)splitViewController:(UISplitViewController *)splitViewController
   showDetailViewController:(UIViewController *)vc
                     sender:(id)sender {
    NSLog(@"UISplitViewController collapsed: %d", splitViewController.collapsed);

    // TODO: add introspection
    if (splitViewController.collapsed) {
        UITabBarController *master = (UITabBarController *) splitViewController.viewControllers[0];
        UINavigationController *masterNavigationController = (UINavigationController *)master.selectedViewController;

        // push detail view on the navigation controller
        //[masterNavigationController pushViewController:vc animated:YES];
        // push was not always working (see discussion in answer below), use showViewController instead
        [masterNavigationController showViewController:vc sender:sender];

        return YES;
    }

    return NO;
}

Ответ 2

Проблема с решением Peter заключается в том, что он будет разваливаться с iPhone 6 +. Как это сделать? С помощью этого кода, если iPhone 6 + находится в портретной ориентации - подробный вид вставляется в стек навигации. Все хорошо, до сих пор. Теперь поверните в пейзаж, а затем вы увидите подробный вид в виде подробного представления и главного представления.

Для реализации двух методов вам понадобится делегат контроллера разделенного представления:

- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)detailVC sender:(id)sender
{
    UITabBarController *masterVC = splitViewController.viewControllers[0];

    if (splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact)
        [masterVC.selectedViewController showViewController:detailVC sender:sender];
    else
        [splitViewController setViewControllers:@[masterVC, detailVC]];

    return YES;
}

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

- (UIViewController*)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
{
    UITabBarController *masterVC = splitViewController.viewControllers[0];

    if ([(UINavigationController*)masterVC.selectedViewController viewControllers].count > 1)
        return [(UINavigationController*)masterVC.selectedViewController popViewControllerAnimated:NO];
    else
        return nil; // Use the default implementation
}

С помощью этого решения все нажимается на стек навигации, когда это необходимо, а также обновляет подробное представление на ландшафте iPad/6 +.

Ответ 3

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

У меня почти такая же структура раскадровки, как и у меня, но поскольку vc есть navigationController, я получаю ошибку времени выполнения, говоря

'Нажатие навигационного контроллера не поддерживается'

Как сказано, это потому, что vc является navigationController подробного представления, а не viewController подробного представления.

Обратите внимание, что я удивлен тем, что @PeterOettl не получает эту ошибку в своем случае также, так как segue, указанный в изображении раскадровки, указывает на контроллер навигации детального вида.

Поэтому код должен понравиться (в Swift) просто добавив

let detailViewControllerNavigationController = (vc as UINavigationController).viewControllers[0] as UIViewController

и нажатием detailViewControllerNavigationController вместо vc

и весь код

func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool {
    println("UISplitViewController collapsed: \(splitViewController.collapsed)")
    if (splitViewController.collapsed) {
        let master = splitViewController.viewControllers[0] as UITabBarController
        let masterNavigationController = master.selectedViewController as UINavigationController

        let detailViewControllerNavigationController = (vc as UINavigationController).viewControllers[0] as UIViewController

        masterNavigationController.pushViewController(detailViewControllerNavigationController, animated: true)

        return true
    } else {
        return false
    }
}

Также обратите внимание, что этот код помещается в AppDelegate.swift примера мастер-детали Xcode, где в главном представлении добавлена ​​панель вкладок.

ИЗМЕНИТЬ

В комментариях, которые мы обсуждали с @PeterOettl разницы между .pushViewController и .showViewController.

В документации Apple говорится:

showViewController: отправитель:

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

Доступно в iOS 8.0 и более поздних версиях.

Ответ 4

Я реализовал @Dreaming в двоичном ответе в Swift:

func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool {
    let masterVC = splitViewController.viewControllers[0] as UITabBarController

    if splitViewController.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact {
        masterVC.selectedViewController?.showViewController(vc, sender: sender)
    } else {
        splitViewController.viewControllers = [masterVC, vc]
    }

    return true
}

func splitViewController(splitViewController: UISplitViewController, separateSecondaryViewControllerFromPrimaryViewController primaryViewController: UIViewController!) -> UIViewController? {
    let masterVC = splitViewController.viewControllers[0] as UITabBarController

    if let navController = masterVC.selectedViewController as? UINavigationController {
        if navController.viewControllers.count > 1 {
            return navController.popViewControllerAnimated(false)
        }
    }
    return nil
}

Ответ 5

Я ценю эту дискуссию, когда я выполнял одно и то же приложение структуры пользовательского интерфейса, а также сделал его адаптивным для ротации iPhone 6 Plus и многозадачности iPad (слайд-просмотр/разделение, iOS 9 или новее).

Мы поставили полное решение (адаптивный UISplitViewController с UITabBarController в качестве основного контроллера представления), открытый на GitHub indievox-inc/TabBarSplitViewController. Спасибо!