【问题标题】:UIViewControllerRepresentable: Navigation Title and Bar Button Items Ignored in NavigationViewUIViewControllerRepresentable:在 NavigationView 中忽略的导航标题和栏按钮项
【发布时间】:2020-04-05 07:24:54
【问题描述】:
  • 我有一个 UITableViewController 子类,我已将其包裹在 UIViewControllerRepresentable 中。
  • 我在视图控制器中设置了navigationItem.titlenavigationItem.leftBarButtonItems
  • 我将我的 UIViewControllerRepresentable 实例作为 SwiftUI NavigationLink 在 SwiftUI NavigationView 中的目标。
  • 当视图被推送到导航堆栈时,表格视图会出现,但标题和栏按钮项目不会出现。

这里发生了什么?

【问题讨论】:

  • 你能发布一些代码来重现吗?

标签: uiviewcontroller uikit swiftui uinavigationitem navigationview


【解决方案1】:

解决了!

问题与期待 SwiftUI 在后台使用 UINavigationController。因此,如果我使用 UIViewControllerRepresentable 将 UIViewController 推送到 SwiftUI NavigationView 上,那么我希望该视图控制器的导航项和工具栏项被所述导航控制器使用。正如我上面提到的,它们被忽略了。

根本原因 事实证明,标题和项目被忽略了,因为我的视图控制器的父级不是预期的 UINavigationController。相反,它的父级是 SwiftUI 在后台使用的中间包装视图控制器,然后将其推送到导航控制器上。它忽略了标题和项目,因为导航控制器正在向包装器询问其项目(没有项目),而不是我的视图控制器。

UIKit 解决方案 所以,如果你想从你的 UIKit 视图控制器设置标题或栏按钮项目或工具栏项目,那么你需要在它的父级上设置它们:

self.parent?.navigationItem.title = "My Title"

此外,您不能从 viewDidLoad 执行此操作,因为此时视图控制器似乎还没有被 SwiftUI 父级包装。您必须在 viewWillAppear 中执行此操作。

SwiftUI 解决方案 您还可以从 SwiftUI 设置标题和栏按钮。在您的 UIViewControllerRepresentable 实例上,只需像往常一样添加 .navigationBarTitle 和前导/尾随项目。然后,您可以在 UIViewControllerRepresentable 实现中让按钮与您的视图控制器对话。

【讨论】:

  • 我正在使用你提到的 swiftui 方式,但是我的后退按钮不起作用。
  • 可以使用 didMove(toParent)/willMove(toParent) 吗?
  • 你是一个能解决这个问题的神。在 swiftUI 中使用视图控制器时,我无法弄清楚为什么我们的自定义导航项丢失了。
  • 只针对那些感兴趣的人,我通过更新我的UIViewControllerRepresentable 对象中的父导航项使其工作,如下所示:func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { vc.parent?.navigationItem.title = vc.navigationItem.title vc.parent?.navigationItem.rightBarButtonItems = vc.navigationItem.rightBarButtonItems }
  • 太好了!谢谢
【解决方案2】:

这是一个 UIKit 解决方案,它不需要对 UIViewController 进行内部更改,并且只应在将包装器添加为父级时调用一次。

struct MyViewControllerRepresentable: UIViewControllerRepresentable {

    class Coordinator {
        var parentObserver: NSKeyValueObservation?
    }

    func makeUIViewController(context: Self.Context) -> MyViewController {
        let viewController =  MyViewController()
        context.coordinator.parentObserver = viewController.observe(\.parent, changeHandler: { vc, _ in
            vc.parent?.title = vc.title
            vc.parent?.navigationItem.rightBarButtonItems = vc.navigationItem.rightBarButtonItems
        })
        return viewController
    }

    func updateUIViewController(_ uiViewController: MyViewController, context: Self.Context) {}

    func makeCoordinator() -> Self.Coordinator { Coordinator() }
}

【讨论】:

    【解决方案3】:

    josephap 提出了很好的建议,但是他的 UIKit 解决方案让我的导航栏标题“闪烁”,不像正常情况下那么流畅。

    我的解决方案是从我的 SwiftUI 添加导航标题:

    NavigationLink(destination: <YourUIViewControllerRepresentable>()
                                        .edgesIgnoringSafeArea([.top,.bottom])
                                        .navigationTitle(item.name)) {
                            Text(item.name)
                        }) 
    

    【讨论】:

    • 并非如此,因为在旧版 SDK 中,导航标题需要在一些内部工作之后在 UIViewController 中设置,并且无法事先完成。
    • 也感谢.edgesIgnoringSafeArea 的提示,我想知道为什么我的 UIKit 视图不能正确全屏显示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 2019-10-27
    • 1970-01-01
    • 2014-10-13
    相关资源
    最近更新 更多