UINavigationController внутри UITabBarController внутри UISplitViewController, представленный модально на iPhone
У меня есть UISplitViewController, который содержит UITabBarController как главный вид.
Этот UITabBarController содержит UINavigationController. Детальный вид содержит также UINavigationController.
![Storyboard]()
На iPad это работает так, как ожидалось. Сегмент show segue представляет изображение в навигационном контроллере на подробном представлении.
На iPhone, с другой стороны, я ожидал, что фрагмент show detail segue подталкивает подробный вид в стек навигационного контроллера основного вида. Но на самом деле оно представлено по образцу мастера.
При удалении UITabBarController из раскадровки и использовании UINavigationController непосредственно в главном представлении это работает.
Есть ли у кого-нибудь идея, как я мог бы представить подробный вид на стек главного мастера UINavigationController на iPhone?
Ответы
Ответ 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. Спасибо!