【问题标题】:UINavigationController inside UITabBarController inside UISplitViewController (still) shows detail controller modally instead of pushingUISplitViewController 内的 UITabBarController 内的 UINavigationController (仍然)以模态方式显示详细控制器,而不是推送
【发布时间】:2019-09-09 12:09:12
【问题描述】:

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

  • 如果我在垂直 iPhone 上,要么将详细视图控制器推送到堆栈中
  • 在 lanscape iPhone 6+ 和其他更大的屏幕(如 iPad 等)上的 UISplitViewController 的 detailViewController 中显示细节控制器

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

但是这些问题中提到的解决方案都不起作用。其中一些创建了一个无限递归循环和一个EXC_BAD_ACCESS。而我尝试的最新版本只是简单地以模态方式呈现细节视图控制器,而不是将其推送到 iPhone 上的堆栈中。我所做的是创建一个自定义的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 实现中发生了一些变化。

有人有什么建议吗?

【问题讨论】:

  • 实际显示详细视图控制器的代码是什么样的?
  • 我编辑了我的问题以添加此代码。

标签: ios swift uinavigationcontroller uitabbarcontroller uisplitviewcontroller


【解决方案1】:

我想通了。事实上,它与我试图展示的目标视图控制器有关。我在 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 上都能完美运行

【讨论】:

    【解决方案2】:

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

    splitViewController.showDetailViewController(vc, sender: self)
    

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

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

    【讨论】:

    • 你建议我怎么称呼它?
    猜你喜欢
    • 2014-11-08
    • 2015-03-10
    • 1970-01-01
    • 2015-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-30
    • 2014-11-10
    相关资源
    最近更新 更多