在我的UISplitViewController中,主视图是一个包含UITableViewController的UINavigationController。有时,当用户选择表中的项时,我必须在主视图中将另一个tableViewController压到现有表上。
在iOS 7中,在我的第一个UITableViewController中,我只需要调用
[self.navigationController pushViewController:otherTableVC animated:YES];
在iOS 8中:
折叠拆分视图时,otherTableVC将成为详细视图! 然后旋转设备后,我们并排看到两张桌子......
更糟糕的是,如果设备显示两个窗格,则代码工作正常,第二个表在主视图中被推到第一个窗格。但是,经过两次旋转后,两张桌子又是并排的。似乎UISplitViewController的折叠模式干扰了我自己的导航控制器...
如何在主视图中管理自己的UINavigationController?
谢谢
编辑:
我的主视图和详细信息视图都有一个导航控制器。为了解决我的问题,我刚刚发现,在折叠模式下,我必须创建一个额外的导航控制器并将其推到主导航控制器上。
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:otherTableVC];
[self.navigationController pushViewController:navController animated:YES];
所以我发现帽子我们可以将导航控制器推到另一个导航控制器中。
答案 0 :(得分:24)
简短回答,您可以通过UISplitViewControllerDelegate方法控制此行为:
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
我怀疑你真正想要做的是处理你有一个基于iOS 8 UISplitViewController的应用程序的情况,你的主要和详细视图都是UINavigationControllers,并且你想要的是一些viewControllers(在这些导航控制器中)仅出现在拆分视图的主要或细节一侧。以下答案涉及此问题。它还可以处理您有时希望视图替换Detail导航控制器中的视图而不是被推到那里的情况。
一个小警告:下面的代码并不涉及所有可能的情况,并且有一些假设:
我不建议只实现splitViewController的一面:collapseSecondaryViewController:ontoPrimaryViewController:/ splitViewController:separateSecondaryViewControllerFromPrimaryViewController:logic并取决于另一方的默认实现。 Apple做了一些奇怪的事情,例如将UINavigationViewController从Detail侧放入主要侧作为Primary导航控制器堆栈中的一个viewControllers,然后推送其上方的其他视图控制器,即使你完全理解仍然不能从您自己的代码复制。因此,最好自己处理这两个过程。
这就是我使用的:
#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's 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;
}
答案 1 :(得分:0)
Swift 4版本,进行了较小的更改以使其与我的代码兼容:
func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
if !isCollapsed {
// in expanded mode set new VC as top view controller of the detail nav controller
if let detailNavigationController = viewControllers[1] as? UINavigationController {
detailNavigationController.setViewControllers([vc], animated: false)
}
} else {
// in collapsed mode push the new view controller on the master nav controller
if let masterNavigationController = viewControllers[0] as? UINavigationController {
masterNavigationController.pushViewController(vc, animated: true)
}
}
return true
}
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
let masterNavigationController = primaryViewController as? UINavigationController
let detailNavigationController = secondaryViewController as? UINavigationController
let episodeDetailViewController = detailNavigationController?.viewControllers.first as? EpisodeDetailTableViewController
if episodeDetailViewController?.episode == nil {
// detail view is blank. We do not need to push this onto the master
return true
}
guard var newMasterViewControllers = masterNavigationController?.viewControllers else { return false }
newMasterViewControllers.append(contentsOf: detailNavigationController?.viewControllers ?? [])
masterNavigationController?.setViewControllers(newMasterViewControllers, animated: false)
return true
}
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
let masterNavigationViewController = primaryViewController as? UINavigationController
var newMasterViewControllers = [UIViewController]()
var newDetailViewControllers = [UIViewController]()
for vc in masterNavigationViewController?.viewControllers ?? [] {
if vc is PodcastsTableViewController || vc is EpisodesTableViewController {
newMasterViewControllers.append(vc)
} else {
newDetailViewControllers.append(vc)
}
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let detailNavigationController = storyboard.instantiateViewController(withIdentifier: "splitViewDetailViewController") as! UINavigationController
if newDetailViewControllers.count == 0 {
let emptyEpisodeDetailViewController = storyboard.instantiateViewController(withIdentifier: "episodeDetail")
newDetailViewControllers.append(emptyEpisodeDetailViewController)
}
masterNavigationViewController?.setViewControllers(newMasterViewControllers, animated: false)
detailNavigationController.setViewControllers(newDetailViewControllers, animated: false)
return detailNavigationController
}