【问题标题】:UISplitViewController's detail view push errorUISplitViewController的详细视图推送错误
【发布时间】:2015-08-16 12:39:39
【问题描述】:

我正在为 iOS8 使用 UISplitViewController 实现一个通用应用程序,遇到 UINavigation 的奇怪问题,非常感谢您的专业知识。

我的项目具有以下 StoryBoard 布局:

在 iPad 上,一切正常。但是,在 iPhone 上运行时,导航无法按预期工作。请参阅此short video 演示当我从“详细屏幕 2”导航回“详细屏幕 1”时的导航问题。

我尝试在一个全新的项目中实现相同的场景,但没有发现问题。只有在移植到我现有的项目后,我才会看到这种行为。

更新 1

这是我的 AppDelegate 代码:

    @interface AppDelegate () <UISplitViewControllerDelegate>

    @end

    @implementation AppDelegate

    -(BOOL) application: (UIApplication*) application didFinishLaunchingWithOptions: (NSDictionary*) launchOptions {

        UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
        UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
        navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem;
        splitViewController.delegate = self;

        splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;

        return YES;
    }

    #pragma mark - Split view

    - (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {

        return YES;
    }

....
@end

更新 2:

感谢 PetahChristian,我认为他在下面的观察是正确的:

折叠具有导航的辅助视图控制器 控制器,Apple 将辅助导航控制器插入到 主导航控制器的堆栈。所以,对于 iPhone,你在哪里 看到问题,看起来只有一个导航 控制器,但实际上有两个。

假设观察是正确的,如何防止辅助导航控制器推到主导航控制器上? UISplitViewControllerDelegate 方法仅处理直接链接到 UISplitViewController 的辅助视图控制器的折叠逻辑。在我的例子中,要折叠的辅助视图控制器(即 Detail VC1)是通过主视图控制器的“Show Detail (eg Replace)”segue 和 @ 987654328@ 方法在此转换期间未执行。

在全新项目中使用完全相同的设置,Apple 不会将辅助导航控制器插入主导航控制器,我在新项目中也没有遇到此问题。

非常感谢。

【问题讨论】:

  • 我阅读了您更新的问题。辅助视图控制器实际上是辅助导航控制器。看看你的故事板。您可以看到辅助导航控制器,Detail VC1 作为其子级。当 splitView 折叠时,辅助导航控制器必须在主导航控制器上折叠。 Apple 确实将辅助导航控制器插入到主视图控制器中。这就是他们测试[secondaryViewController isKindOfClass:[UINavigationController class]]... 的原因,有关更多详细信息,请参阅我的答案。
  • 谢谢 PetahChristain。我非常感谢你在这个主题上的帮助,你帮助我更多地了解了 UISplitViewControllerDelegate。我找到了问题的罪魁祸首,并在下面发布了我的答案。再次感谢。

标签: ios iphone uinavigationcontroller uinavigationbar uisplitviewcontroller


【解决方案1】:

在我的项目中导致这种导航特性的罪魁祸首是由于我从 SO 用户下载的名为 UIViewController+BackButtonHandler 的扩展。这个处理程序拦截了导航返回按钮,所以当用户按下返回时我可以有机会做额外的工作。此类别扩展代码覆盖 navigationBar:shouldPopItem: 导致默认导航中断。我不知道这段代码正在执行,因为我没有使用它,而是将其合并到我的项目中。哇... 2 天把我的头撞到墙上。

【讨论】:

  • 很高兴您发现了问题!一个好的经验法则是,如果我们必须“解决”Apple 的做事方式,我们很可能会错过处理它的正确方法。如果您问 SO 在用户回击时如何做额外的工作,您可能会找到一种更好的方法来完成它,它不涉及拦截正常行为:)
  • @Loc Pham 你拯救了我的一天
【解决方案2】:

由于UISplitViewControllerDelegate 代码不同,它在项目之间的行为不同。

新项目有必要的代码,但现有项目可能缺少它。

检查您的 AppDelegate 并比较处理折叠和分离辅助视图控制器的代码。

-splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
-splitViewController:separateSecondaryViewControllerFromPrimaryViewController:

更新:

您不应该在splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: 中无条件地返回YES。您需要首先确定哪个视图控制器位于顶部:看看他们如何检查它是否是(辅助导航控制器及其子)详细视图控制器,并且它有详细信息要显示?

- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
    if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]] && ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) {
        // Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
        return YES;
    } else {
        return NO;
    }
}

更新 2:

为了折叠具有导航控制器的辅助视图控制器,Apple 将辅助导航控制器插入到主导航控制器的堆栈中。所以,对于 iPhone,你看到问题的地方,看起来只有一个导航控制器,但实际上有两个。

在您的视频中,当您看起来像是在主导航时,但它有一个后退按钮,您点击它,后退按钮滑出屏幕,这就是辅助导航控制器从主导航控制器中消失。

为了使您的项目正常工作,您必须像苹果一样有条件地测试导航控制器,以确定(导航控制器及其子)细节视图控制器是否被丢弃。

更新 3:

导航控制器本身就是一个视图控制器。它控制其子视图控制器。

辅助导航控制器辅助视图控制器。详细视图控制器是它的子视图控制器。

splitView 委托方法处理的是二级导航控制器的折叠或分离,它恰好有一个或多个子视图控制器。

当 splitView 控制器折叠时,主导航控制器的堆栈看起来像 [masterViewController, secondaryNavigationController]。

至于替换segue,您要替换的是Storyboard 底部的Empty 详细视图控制器,带有橙色的详细信息屏幕1。但是替换的详细视图控制器仍然有一个父级,即辅助导航控制器。并且当 splitViewController 折叠时,辅助导航控制器最终位于主导航控制器堆栈上。你看不到这个,因为它是透明的。您所看到的只是详细信息屏幕 1,因为它是辅助导航控制器的顶视图控制器。

您的 splitViewDelegate 代码已损坏。这就是当您点击后退按钮时视图控制器无法在视频中正确设置动画的原因。修复委托代码,所有看起来和正常工作。

您肯定需要折叠方法和分离方法,它们需要做正确的事情。这就是为什么我建议您使用 Apple 的代码,而不是尝试编写自己的代码,因为 Apple 的代码正确地折叠并分离了导航控制器。

【讨论】:

  • 我的 UISplitViewControllerDelegate 方法很简单,它只是为 splitViewController:collapseSecondaryViewController:ontoPrimaryViewController: 返回 YES,而我没有实现 -splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
  • 发布您的UISplitViewControllerDelegate 代码。其中有一个错误,因为现有项目没有正确处理主要和次要视图控制器。这就是影响视图正确弹出导航控制器堆栈的原因。
  • 我修改了我的问题以包含 AppDelegate 代码。谢谢。
  • 你必须正确地实现这两种方法,否则它会在何时分离辅助视图控制器时做出错误的决定。这就是视图没有正确弹出的原因。正如我在回答中提到的,它在新项目中有效,因为那里有正确的代码(Apple 包含在新项目中)。注释掉您的代码,并为这两种方法复制他们的代码,您应该会看到它有效。他们的代码在那里是有原因的。 :)
  • 让我迷惑的是工作项目没有实现:-splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-24
  • 1970-01-01
相关资源
最近更新 更多