Ответ 1
Короткий ответ, вы можете контролировать это поведение с помощью методов UISplitViewControllerDelegate:
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
Я подозреваю, что вы действительно хотите сделать, это разобраться с ситуацией, когда у вас есть приложение на базе iOS 8 UISplitViewController, где ваши первичные и подробные представления являются как UINavigationControllers, так и некоторыми контроллерами viewControllers (в пределах этих контроллеров навигации), которые вы хотите отображаются только на основной или детальной стороне раскола. Ниже приведен ответ. Он также справляется с ситуацией, когда вы иногда хотите, чтобы представление заменяло представления в контроллере навигации Detail, а не нажималось туда.
Небольшое предостережение: приведенный ниже код не касается всех возможных случаев и имеет некоторые предположения:
- Мы не ожидаем, что что-либо может измениться в стеке Подробного навигационного контроллера, когда сплит-представление свернуто, и эти представления затенены подробным представлением над ними.
- В наших подклассах UIViewController есть свойство shouldDisplayInDetailedView и shouldReplaceDetailedView
- Мы предполагаем, что мы только нажимаем представления на подробный контроллер навигации, у которого есть свойство shouldDisplayInDetailedView.
- Контроллеры просмотра добавляются в сторону Detail через splitViewController: showDetailViewController: или pushViewController: анимированный: в свойстве navigationController представления в подробном представлении (в развернутом или свернутом состоянии).
- Контроллеры просмотра, которые должны заменить контроллеры представлений в контроллере навигации Detail, добавляются только через splitViewController: showDetailViewController: и только из взаимодействия с представлением в контроллере Primary view, т.е. это может произойти только в том случае, если контроллер Primary view не затенен когда в сложенном состоянии.
- У нас есть BlankViewController для отображения в подробном представлении, когда контроллер разделенного представления расширяется, но у нас есть только контроллеры представлений, которые должны оставаться на главной стороне.
Я не рекомендую применять только одну сторону splitViewController: collapseSecondaryViewController: onPrimaryViewController:/splitViewController: отдельныйSecondaryViewControllerFromPrimaryViewController: логический и в зависимости от реализации по умолчанию для другой стороны. Apple делает некоторые странные вещи, такие как включение UINavigationViewController из стороны Detail в основную сторону в качестве одного из контроллеров viewControlers в стеке контроллера первичной навигации, а затем нажатия на другие контроллеры представлений над ним, которые даже если вы полностью понимаете, что они не могут быть реплицированы из ваш собственный код. Таким образом, лучше всего справляться с обеими сторонами процесса.
Это то, что я использую:
#pragma mark -
#pragma mark Split View Controller delegate.
- (BOOL)splitViewController:(UISplitViewController *)splitViewController showViewController:(UIViewController *)vc sender:(id)sender
{
//Standard behaviour. This won't get called in our case when the split view is collapsed and the primary view controllers are obscured.
return NO;
}
// Since we treat warnings as errors, silence warning about unknown selector below on UIViewController subclasses.
#pragma GCC diagnostic ignored "-Wundeclared-selector"
- (BOOL)splitViewController:(UISplitViewController *)splitViewController showDetailViewController:(UIViewController *)vc sender:(id)sender
{
if (splitViewController.collapsed == NO)
{
// The navigation controller we'll be adding the view controller vc to.
UINavigationController *navController = splitViewController.viewControllers[1];
UIViewController *topDetailViewController = [navController.viewControllers lastObject];
if ([topDetailViewController isKindOfClass:[BlankViewController class]] ||
([vc respondsToSelector:@selector(shouldReplaceDetailedView)] && [vc performSelector:@selector(shouldReplaceDetailedView)]))
{
// Replace the (expanded) detail view with this new view controller.
[navController setViewControllers:@[vc] animated:NO];
}
else
{
// Otherwise, just push.
[navController pushViewController:vc animated:YES];
}
}
else
{
// Collapsed. Just push onto the conbined primary and detailed navigation controller.
UINavigationController *navController = splitViewController.viewControllers[0];
[navController pushViewController:vc animated:YES];
}
// We've handled this ourselves.
return YES;
}
- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController
{
UINavigationController *primaryNavController = (UINavigationController *)primaryViewController;
UINavigationController *secondaryNavController = (UINavigationController *)secondaryViewController;
UIViewController *bottomSecondaryView = [secondaryNavController.viewControllers firstObject];
if ([bottomSecondaryView isKindOfClass:[BlankViewController class]])
{
NSAssert([secondaryNavController.viewControllers count] == 1, @"BlankViewController is not only detail view controller");
// If our secondary controller is blank, do the collapse ourself by doing nothing.
return YES;
}
// We need to shift these view controllers ourselves.
// This should be the primary views and then the detailed views on top.
// Otherwise the UISplitViewController does wacky things like embedding a UINavigationController inside another UINavigation Controller, which causes problems for us later.
NSMutableArray *newPrimaryViewControllers = [NSMutableArray arrayWithArray:primaryNavController.viewControllers];
[newPrimaryViewControllers addObjectsFromArray:secondaryNavController.viewControllers];
primaryNavController.viewControllers = newPrimaryViewControllers;
return YES;
}
- (UIViewController *)splitViewController:(UISplitViewController *)splitViewController separateSecondaryViewControllerFromPrimaryViewController:(UIViewController *)primaryViewController
{
UINavigationController *primaryNavController = (UINavigationController *)primaryViewController;
// Split up the combined primary and detail navigation controller in their component primary and detail view controller lists, but with same ordering.
NSMutableArray *newPrimaryViewControllers = [NSMutableArray array];
NSMutableArray *newDetailViewControllers = [NSMutableArray array];
for (UIViewController *controller in primaryNavController.viewControllers)
{
if ([controller respondsToSelector:@selector(shouldDisplayInDetailedView)] && [controller performSelector:@selector(shouldDisplayInDetailedView)])
{
[newDetailViewControllers addObject:controller];
}
else
{
[newPrimaryViewControllers addObject:controller];
}
}
if (newDetailViewControllers.count == 0)
{
// If there no detailed views on the top of the navigation stack, return a blank view (in navigation controller) for detailed side.
UINavigationController *blankDetailNavController = [[UINavigationController alloc] initWithRootViewController:[[BlankViewController alloc] init]];
return blankDetailNavController;
}
// Set the new primary views.
primaryNavController.viewControllers = newPrimaryViewControllers;
// Return the new detail navigation controller and views.
UINavigationController *detailNavController = [[UINavigationController alloc] init];
detailNavController.viewControllers = newDetailViewControllers;
return detailNavController;
}