在 iOS 8 中 UISplitViewController 的主视图中有一个 UINavigationController [英] Having a UINavigationController in the master view of a UISplitViewController in iOS 8

查看:18
本文介绍了在 iOS 8 中 UISplitViewController 的主视图中有一个 UINavigationController的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my UISplitViewController, the master view is a UINavigationController containing a UITableViewController. Sometime, when the user selects an item in the table, I have to push another UITableViewController over the existing table in the master view.

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

In iOS 7, inside my first UITableViewController I just call

[self.navigationController pushViewController:otherTableVC animated:YES];

在 iOS 8 中:

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

When the split view is collapsed, the otherTableVC becomes the detail View! Then after rotating the device, we see the two tables side by side...

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

Worse, if the device shows the two panes, the code works great and the second table is pushed over the first one in the master view. But, after a double rotation, the two tables are again side by side. It seems the collapsed mode of the UISplitViewController interferes with my own navigation controller…

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

How can I manage my own UINavigationController in the Master View?

谢谢

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

My both primary and details views have a navigation Controller. And to solve my problem, I just discovered that, in collapsed mode, I have to create an extra Navigation Controller and push it over the primary navigation controller.

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:otherTableVC];
[self.navigationController pushViewController:navController animated:YES];

所以我刚刚发现我们可以将导航控制器推入另一个导航控制器.

So I just discovered hat we can push a navigation Controller inside another Navigation Controller.

推荐答案

简短的回答,您可以通过 UISplitViewControllerDelegate 方法控制此行为:

Short answer, you can control this behaviour via the UISplitViewControllerDelegate methods:

splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:

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

I suspect what you really want to do is deal with the situation where you have an iOS 8 UISplitViewController-based app where your primary and detailed views are both UINavigationControllers and there are some viewControllers (within these navigation controllers) that you want to appear only on the primary or detail side of the split view. The answer below deals with this. It also copes with the situation where you sometimes wish for a view to replace the views in the Detail navigation controller, rather than getting pushed there.

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

A small caveat: the code below does not deal with all possible cases and has some assumptions:

  • 当拆分视图折叠并且这些视图被其上方的详细视图遮挡时,我们预计详细导航控制器堆栈上不会发生任何变化.
  • 我们的 UIViewController 子类都有一个 shouldDisplayInDetailedView 和 shouldReplaceDetailedView 属性
  • 我们假设我们只将视图推送到设置了 shouldDisplayInDetailedView 属性的详细导航控制器上.
  • 视图控制器通过 splitViewController:showDetailViewController: 或 pushViewController:animated: 添加到详细视图中视图的 navigationController 属性(处于展开或折叠状态).
  • 应该替换 Detail 导航控制器中的视图控制器的视图控制器只能通过 splitViewController:showDetailViewController: 添加,并且只能通过与主视图控制器中的视图交互来添加,也就是说,只有在以下情况下才会发生这种情况处于折叠状态时,主视图控制器不会被遮挡.
  • 当拆分视图控制器展开时,我们有一个 BlankViewController 显示在详细视图中,但我们只有应该保留在主端的视图控制器.
  • We don't expect anything can change on the Detailed navigation controller stack when the split view is collapsed and those views are obscured by a detailed view above them.
  • Our UIViewController subclasses all have a shouldDisplayInDetailedView and shouldReplaceDetailedView property
  • We assume that we only push views onto the detailed navigation controller that have the shouldDisplayInDetailedView property set.
  • View controllers are added to the Detail side via splitViewController:showDetailViewController: or a pushViewController:animated: on the navigationController property of a view within a detailed view (in either expanded or collapsed state).
  • View controllers that should replace the view controllers in the Detail navigation controller are only added via splitViewController:showDetailViewController: and only from interaction with view in the Primary view controller, i.e., this can only happen if the Primary view controller is not obscured when in collapsed state.
  • We have a BlankViewController to display in the Detail View when the split view controller gets expanded but we only have view controllers that should stay on the Primary side.

我不建议只实现 splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:/splitViewController:separateSecondaryViewControllerFromPrimaryViewController: 逻辑的一侧,并取决于另一侧的默认实现.Apple 做了一些奇怪的事情,例如将 UINavigationViewController 从 Detail 端放入主端,作为主导航控制器堆栈中的 viewControllers 之一,然后将其他视图控制器推到其上方,即使您完全理解仍然无法从中复制你自己的代码.因此,最好自己处理流程的双方.

I don't recommend implementing only one side of the splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: / splitViewController: separateSecondaryViewControllerFromPrimaryViewController: logic and depending on the default implementation for the other side. Apple do some strange things like putting the UINavigationViewController from the Detail side into the primary side as one of the viewControllers in the Primary navigation controller stack but then pushing other view controllers above it, which even if you understand completely still can't be replicated from your own code. Thus its best to handle both sides of the process yourself.

这是我用的:

#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;
}

这篇关于在 iOS 8 中 UISplitViewController 的主视图中有一个 UINavigationController的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆