如何从SwiftUI跳转带返回按钮的UINavigation式UIViewController?
解决SwiftUI与UIKit导航栏重叠问题
我明白你遇到的问题:用NavigationLink跳转到封装了UINavigationController的UIViewControllerRepresentable时,出现了两套导航栏——SwiftUI自带的导航栏有返回按钮,而你自己创建的UIKit导航栏没有,你想要保留UIKit的导航栏并添加返回按钮,同时隐藏SwiftUI的那一套。
下面是具体的解决方案,分两步走:
1. 修正UIKit视图封装代码,添加返回按钮回调
首先,你需要给UIKit的视图控制器添加返回按钮,并且通过Coordinator让它能通知SwiftUI关闭页面。同时要注意,不要把UINavigationController作为结构体的属性(结构体是值类型,容易重复创建),而是在makeUIViewController方法内创建:
struct UIKitVc: UIViewControllerRepresentable { // 定义关闭回调,用于UIKit通知SwiftUI返回 var onDismiss: () -> Void // 创建Coordinator,处理UIKit与SwiftUI的交互 func makeCoordinator() -> Coordinator { Coordinator(self) } func makeUIViewController(context: Context) -> UINavigationController { let storyboard = UIStoryboard(name: "Main", bundle: nil) let viewController = storyboard.instantiateViewController(withIdentifier: "SearchResult") as! SearchResultViewController // 给UIKit的视图控制器添加自定义返回按钮 let backButton = UIBarButtonItem(title: "返回", style: .plain, target: context.coordinator, action: #selector(Coordinator.dismiss)) viewController.navigationItem.leftBarButtonItem = backButton // 用目标VC作为导航控制器的根视图 let navigationController = UINavigationController(rootViewController: viewController) return navigationController } func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {} class Coordinator: NSObject { var parent: UIKitVc init(_ parent: UIKitVc) { self.parent = parent } // 触发SwiftUI的关闭动作 @objc func dismiss() { parent.onDismiss() } } }
2. 在SwiftUI中隐藏自带导航栏并绑定关闭动作
接下来,在使用NavigationLink(或navigationDestination)时,隐藏SwiftUI的导航栏,并绑定关闭回调,让UIKit的返回按钮能触发页面返回:
如果你使用的是iOS 16+的NavigationStack:
struct ContentView: View { @State private var isPresentingUIKitVc = false var body: some View { NavigationStack { Button("打开UIKit搜索结果页") { isPresentingUIKitVc = true } .navigationDestination(isPresented: $isPresentingUIKitVc) { UIKitVc(onDismiss: { isPresentingUIKitVc = false }) .navigationBarHidden(true) // 隐藏SwiftUI的导航栏 } } } }
如果你使用的是iOS 15及以前的NavigationView:
struct ContentView: View { @State private var isPresentingUIKitVc = false var body: some View { NavigationView { Button("打开UIKit搜索结果页") { isPresentingUIKitVc = true } .navigationLink(isActive: $isPresentingUIKitVc) { UIKitVc(onDismiss: { isPresentingUIKitVc = false }) .navigationBarHidden(true) // 隐藏SwiftUI的导航栏 } label: { EmptyView() } } } }
为什么原来会出现两套导航栏?
因为NavigationLink会自动将目标视图嵌入到SwiftUI的导航栈中,所以SwiftUI的导航栏会默认显示;而你在UIKitVc中又创建了一个独立的UINavigationController,两者叠加就出现了双导航栏的问题。通过.navigationBarHidden(true)可以完全隐藏SwiftUI的导航栏,同时我们手动给UIKit的导航栏添加了返回按钮,实现了符合你需求的导航体验。
内容的提问来源于stack exchange,提问作者Bumaza
相关产品推荐
相关产品推荐

