You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI点击Button跳转带Navigation Controller的UIKit ViewController

SwiftUI点击Button跳转带Navigation Controller的UIKit ViewController实现方案

你可以根据实际交互需求选择模态弹出、导航栈Push两种实现路径,核心通过UIKit与SwiftUI的原生桥接能力实现,无需额外依赖。


方案1:模态弹出整个UIKit导航栈

适合不需要嵌入现有SwiftUI导航流、独立弹出UIKit业务模块的场景,实现成本最低:

  1. 先加一个通用扩展,让UIViewController可以直接作为SwiftUI视图内容使用
  2. 在Button的点击事件中通过.sheet触发弹窗,弹窗内直接返回嵌入了目标VC的UINavigationController即可

完整可运行代码:

import SwiftUI

// 通用扩展:让所有UIViewController可直接在SwiftUI中作为视图返回
extension UIViewController: UIViewControllerRepresentable {
    public func makeUIViewController(context: Context) -> UIViewController { self }
    public func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

// 你的目标UIKit业务页面,按常规UIKit写法实现即可
class TargetBusinessVC: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        title = "UIKit业务页"
        // 示例:添加关闭按钮
        navigationItem.leftBarButtonItem = UIBarButtonItem(
            barButtonSystemItem: .close,
            target: self,
            action: #selector(dismissPage)
        )
    }
    
    @objc private func dismissPage() {
        dismiss(animated: true)
    }
}

// SwiftUI调用页
struct HomePageView: View {
    @State private var showUIKitModule = false
    
    var body: some View {
        Button("打开UIKit模块") {
            showUIKitModule = true
        }
        .sheet(isPresented: $showUIKitModule) {
            // 把目标VC嵌入导航控制器后直接返回
            UINavigationController(rootViewController: TargetBusinessVC())
                .ignoresSafeArea()
        }
    }
}

方案2:Push到现有SwiftUI导航栈

适合当前SwiftUI页面已经在NavigationStack/NavigationView导航栈内,需要把UIKit页面压入导航栈的场景。注意不要直接把UINavigationController塞进navigationDestination,会导致双导航栏冲突,需要通过桥接组件实现:

// 导航桥接组件:负责找到当前导航控制器执行push操作
struct UIKitPushBridge: UIViewControllerRepresentable {
    @Binding var isActive: Bool
    let buildTargetVC: () -> UIViewController
    
    func makeCoordinator() -> Coordinator { Coordinator(parent: self) }
    
    func makeUIViewController(context: Context) -> UIViewController {
        let anchorVC = UIViewController()
        anchorVC.view.backgroundColor = .clear
        return anchorVC
    }
    
    func updateUIViewController(_ anchorVC: UIViewController, context: Context) {
        guard isActive,
              let navController = anchorVC.navigationController else { return }
        // 避免重复push
        guard !(navController.topViewController?.isKind(of: TargetBusinessVC.self) ?? false) else {
            isActive = false
            return
        }
        navController.pushViewController(buildTargetVC(), animated: true)
        DispatchQueue.main.async {
            isActive = false
        }
    }
    
    class Coordinator: NSObject {
        let parent: UIKitPushBridge
        init(parent: UIKitPushBridge) { self.parent = parent }
    }
}

// 调用示例
struct HomePageView: View {
    @State private var pushToUIKitPage = false
    
    var body: some View {
        NavigationStack {
            Button("Push打开UIKit页面") {
                pushToUIKitPage = true
            }
            .background {
                UIKitPushBridge(isActive: $pushToUIKitPage) {
                    // 这里返回你要push的目标UIKit VC,不需要额外包UINavigationController,会复用现有导航栈
                    TargetBusinessVC()
                }
            }
            .navigationTitle("SwiftUI首页")
        }
    }
}

注意事项

  • 模态弹出场景必须给UINavigationController加.ignoresSafeArea(),否则导航栏会被安全区截断
  • Push场景下目标VC不需要额外嵌套UINavigationController,会自动复用SwiftUI导航栈的导航控制器,避免双导航栏问题
  • 如果点击按钮无响应,先检查@State触发标记是否正确更新,确认当前页面没有其他正在展示的弹窗/sheet
  • 如果UIKit页面导航按钮点击无响应,检查按钮的target/action是否正确绑定,避免循环引用导致VC提前释放

内容的提问来源于stack exchange,提问作者Mazharul Belal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 19:03:41