UINavigationController inside UITabBarController inside UISplitViewController(仍然)以模态方式显示细节控制器而不是推送

UINavigationController inside UITabBarController inside UISplitViewController (still) shows detail controller modally instead of pushing

我的通用应用程序中有一个似乎非常常见的设置,根 UISplitViewController,使用 UITabBarController 作为 masterViewController,然后我想:

为此,我的设置与所有提到类似问题的讨论中描述的设置完全相同:

但是这些问题中提到的 none 解决方案有效。其中一些创建了一个无限递归循环和一个 EXC_BAD_ACCESS。我尝试的最新一个只是简单地以模态方式呈现细节视图控制器,而不是在 iPhones 上将其推入堆栈。我所做的是创建一个自定义 UISplitViewController 子类:

    class RootSplitViewController: UISplitViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            self.delegate = self
        }
    }

    extension RootSplitViewController: UISplitViewControllerDelegate {
        func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
            if let tabController = splitViewController.viewControllers[0] as? UITabBarController {
                if(splitViewController.traitCollection.horizontalSizeClass == .compact) {
                    tabController.selectedViewController?.show(vc, sender: sender)
                } else {
                    splitViewController.viewControllers = [tabController, vc]
                }
            }

            return true
        }

        func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
            if let tabController = splitViewController.viewControllers[0] as? UITabBarController {
                if let navController = tabController.selectedViewController as? UINavigationController {
                    return navController.popViewController(animated: false)
                } else {
                    return nil
                }
            } else {
                return nil
            }
        }
    }

这里是主视图控制器中显示详细视图控制器的代码:

self.performSegue(withIdentifier: "showReference", sender: ["tags": tags, "reference": reference])

其中 tagsreference 从 Firebase 加载。当然 "showReference" segue 属于 "Show Detail (e.g. Replace)" 类型。

第一个委托方法被正确调用,当我单击 UITabBarController 中的列表中的项目时,断点就证明了这一点。然而细节视图控制器仍然以模态方式呈现在 iPhone 上。不过 iPad 没问题:细节视图控制器出现在右侧,正如预期的那样。

上面提到的大多数答案都已经很老了,一些解决方案是在 Objective-C 中实现的,所以也许我在转换中做错了什么,或者从那时起在 UISplitViewController 实现中发生了一些变化.

有人有什么建议吗?

您是否尝试过 ShowDetailViewController 方法来更改拆分视图控制器中的详细视图控制器。

splitViewController.showDetailViewController(vc, sender: self)

如果您的视图控制器不包含导航控制器,您也可以将其嵌入到导航控制器中。

 let nav = UINavigationController.init(rootViewController: vc)
 splitViewController.showDetailViewController(nav, sender: self)

我明白了。事实上,它与我试图展示的目标视图控制器有关。在 UISplitViewControllerDelegate 中我覆盖的 2 个方法中,只有第一个被调用:

func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
    if let tabController = splitViewController.viewControllers[0] as? UITabBarController {
        if(splitViewController.traitCollection.horizontalSizeClass == .compact) {
            tabController.selectedViewController?.show(vc, sender: sender)
        } else {
            splitViewController.viewControllers = [tabController, vc]
        }
    }

    return true
}

但是我在测试的第一个分支中显示的视图控制器已经嵌入到 UINavigationController 中,所以我实际上是将 UINavigationController 显示到另一个中,在这种情况下模态更有意义。所以在那种情况下,我需要显示 UINavigationController 的顶视图控制器,我认为这是我在委托中重写的第二个方法的目的,但它从未被调用过。所以我通过以下实现就在那里做到了:

extension RootSplitViewController: UISplitViewControllerDelegate {
    func splitViewController(_ splitViewController: UISplitViewController, showDetail vc: UIViewController, sender: Any?) -> Bool {
        if let tabController = splitViewController.viewControllers[0] as? UITabBarController {
            if(splitViewController.traitCollection.horizontalSizeClass == .compact) {
                if let navController = vc as? UINavigationController, let actualVc = navController.topViewController {
                    tabController.selectedViewController?.show(actualVc, sender: sender)
                    navController.popViewController(animated: false)
                } else {
                    tabController.selectedViewController?.show(vc, sender: sender)
                }
            } else {
                splitViewController.viewControllers = [tabController, vc]
            }
        }

        return true
    }
}

这似乎在 iPhone 和 iPad 上都能完美运行