UIViewControllerRepresentable:NavigationView 中忽略的导航标题和栏按钮项

UIViewControllerRepresentable: Navigation Title and Bar Button Items Ignored in NavigationView

这里发生了什么?

已解决!

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

根本原因 结果是标题和项目被忽略了,因为我的视图控制器的 parent 不是预期的 UINavigationController。相反,它 parent 是 SwiftUI 在后台使用的中间包装视图控制器,它又被推送到导航控制器上。它忽略了标题和项目,因为导航控制器正在向包装器询问其项目(具有 none),而不是我的视图控制器。

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

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

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

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

来自 josephap 的好建议但是他的 UIKit 解决方案使我的导航栏标题 'flicker' 不像通常显示的那样流畅。

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

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

这是一个 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() }
}