在iOS 8中的UISplitViewController的主视图中有一个UINavigationController

Pat*_*ckV 12 uinavigationcontroller uisplitviewcontroller ios8

在我的UISplitViewController中,主视图是一个包含UITableViewController的UINavigationController.有时,当用户选择表中的项时,我必须在主视图中的现有表上推送另一个tableViewController.

在iOS 7中,在我的第一个UITableViewController中,我只是调用它

[self.navigationController pushViewController:otherTableVC animated:YES];
Run Code Online (Sandbox Code Playgroud)

在iOS 8中:

折叠拆分视图时,otherTableVC将成为详细视图!旋转设备后,我们并排看到两张桌子......

更糟糕的是,如果设备显示两个窗格,代码工作得很好,第二个表被推到主视图中的第一个表.但是,经过两次旋转后,两张桌子又是并排的.似乎UISplitViewController的折叠模式干扰了我自己的导航控制器......

如何在主视图中管理自己的UINavigationController?

谢谢

编辑:

我的主视图和详细信息视图都有一个导航控制器.为了解决我的问题,我刚刚发现,在折叠模式下,我必须创建一个额外的导航控制器并将其推送到主导航控制器上.

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:otherTableVC];
[self.navigationController pushViewController:navController animated:YES];
Run Code Online (Sandbox Code Playgroud)

所以我发现帽子我们可以将导航控制器推到另一个导航控制器中.

小智 24

简而言之,您可以通过UISplitViewControllerDelegate方法控制此行为:

splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
Run Code Online (Sandbox Code Playgroud)

我怀疑你真正想做的是处理你有一个基于iOS 8 UISplitViewController的应用程序的情况,你的主要和详细视图都是UINavigationControllers,并且你想要只出现一些viewControllers(在这些导航控制器中)拆分视图的主要部分或细节部分.以下答案涉及此问题.它还可以处理您有时希望视图替换Detail导航控制器中的视图而不是被推到那里的情况.

一个小警告:下面的代码不处理所有可能的情况,并有一些假设:

  • 折叠拆分视图时,我们不希望在详细导航控制器堆栈上发生任何变化,并且这些视图会被上面的详细视图遮挡.
  • 我们的UIViewController子类都有一个shouldDisplayInDetailedView和shouldReplaceDetailedView属性
  • 我们假设我们只将视图推送到具有shouldDisplayInDetailedView属性集的详细导航控制器.
  • 视图控制器被添加到经由splitViewController的详细侧:showDetailViewController:或其pushViewController:动画:在视图上的详细视图内的navigationController属性(在任一展开或折叠的状态).
  • 应该替换 Detail导航控制器中的视图控制器的视图控制器仅通过splitViewController:showDetailViewController添加:并且仅从主视图控制器中与视图的交互添加,即,只有在折叠时主视图控制器未被遮挡时才会发生这种情况.州.
  • 当拆分视图控制器扩展时,我们有一个BlankViewController可以在详细信息视图中显示,但我们只有视图控制器应该保留在主端.

我不建议只实现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;
}
Run Code Online (Sandbox Code Playgroud)