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

SwiftUI与UIKit混合项目通用导航类的最优架构实现方案

SwiftUI与UIKit混合项目的全局复用导航架构实现

最佳架构选择

采用全局导航协调器+跨端页面容器的方案:用UIKit的UINavigationController作为底层统一导航容器,搭配单例协调器管理所有页面跳转;同时封装通用导航栏组件,让SwiftUI和UIKit页面都能直接复用,彻底解决跨框架导航的割裂问题。

具体实现步骤

1. 封装通用导航栏组件

用SwiftUI实现一次,两边页面都能复用,兼顾灵活性和一致性:

// CommonNavigationBar.swift
import SwiftUI

struct CommonNavigationBar: View {
    let title: String
    let leftAction: (() -> Void)?
    let rightAction: (() -> Void)?
    
    var body: some View {
        HStack {
            Button(action: leftAction ?? {}) {
                Image(systemName: "chevron.left")
                    .foregroundColor(.blue)
            }
            
            Spacer()
            
            Text(title)
                .font(.headline)
            
            Spacer()
            
            Button(action: rightAction ?? {}) {
                Image(systemName: "plus")
                    .foregroundColor(.blue)
            }
        }
        .padding(.horizontal, 16)
        .frame(height: 44)
        .background(Color.white)
    }
}

2. 实现全局导航协调器

单例模式管理,统一处理UIKit/SwiftUI页面的跳转、返回逻辑:

// NavigationCoordinator.swift
import UIKit
import SwiftUI

class NavigationCoordinator {
    static let shared = NavigationCoordinator()
    
    private let navigationController: UINavigationController
    
    private init() {
        navigationController = UINavigationController()
        navigationController.navigationBar.isHidden = true // 隐藏系统导航栏,用自定义组件
    }
    
    // 获取根导航控制器
    func rootNavigationController() -> UINavigationController {
        return navigationController
    }
    
    // 跳转UIKit页面
    func pushUIKitVC(_ vc: UIViewController) {
        navigationController.pushViewController(vc, animated: true)
    }
    
    // 跳转SwiftUI页面
    func pushSwiftUIView<Content: View>(_ view: Content) {
        let hostingVC = UIHostingController(rootView: view)
        navigationController.pushViewController(hostingVC, animated: true)
    }
    
    // 页面返回
    func pop(animated: Bool = true) {
        navigationController.popViewController(animated: animated)
    }
    
    // 返回根页面
    func popToRoot(animated: Bool = true) {
        navigationController.popToRootViewController(animated: animated)
    }
}

3. SwiftUI页面适配

直接嵌入通用导航栏,通过协调器处理跳转:

// DetailScreen.swift
import SwiftUI

struct DetailScreen: View {
    // 假设workout是已定义的模型
    let workout: Workout
    
    var body: some View {
        VStack(spacing: 0) {
            // 复用通用导航栏
            CommonNavigationBar(
                title: "详情页",
                leftAction: { NavigationCoordinator.shared.pop() },
                rightAction: {
                    // 示例:跳转到UIKit页面
                    let anotherVC = AnotherUIKitVC()
                    NavigationCoordinator.shared.pushUIKitVC(anotherVC)
                }
            )
            
            ScrollView {
                NavigationLink(destination: WorkoutDetail(workout: workout)) {
                    WorkoutRow(workout: workout)
                }
            }
        }
        .edgesIgnoringSafeArea(.top)
    }
}

// WorkoutDetail.swift
struct WorkoutDetail: View {
    let workout: Workout
    
    var body: some View {
        VStack(spacing: 0) {
            CommonNavigationBar(
                title: workout.name,
                leftAction: { NavigationCoordinator.shared.pop() },
                rightAction: nil
            )
            
            Text("训练详情内容")
                .padding()
        }
        .edgesIgnoringSafeArea(.top)
    }
}

4. UIKit页面适配

通过UIHostingController嵌入通用导航栏,跳转逻辑交给协调器:

// HomeScreenController.swift
import UIKit
import SwiftUI

class HomeScreenController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        // 添加自定义导航栏
        let navBar = CommonNavigationBar(
            title: "首页",
            leftAction: nil,
            rightAction: nil
        )
        let navBarHost = UIHostingController(rootView: navBar)
        addChild(navBarHost)
        view.addSubview(navBarHost.view)
        navBarHost.view.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            navBarHost.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            navBarHost.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            navBarHost.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            navBarHost.view.heightAnchor.constraint(equalToConstant: 44)
        ])
        navBarHost.didMove(toParent: self)
        
        // 添加测试跳转按钮
        let jumpBtn = UIButton(type: .system)
        jumpBtn.setTitle("跳转到SwiftUI详情页", for: .normal)
        jumpBtn.addTarget(self, action: #selector(jumpToSwiftUI), for: .touchUpInside)
        jumpBtn.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(jumpBtn)
        NSLayoutConstraint.activate([
            jumpBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            jumpBtn.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
    
    @objc func jumpToSwiftUI(sender: UIButton!) {
        // 通过协调器跳转SwiftUI页面
        NavigationCoordinator.shared.pushSwiftUIView(DetailScreen(workout: Workout.sample))
    }
}

5. 全局导航初始化

根据项目生命周期类型设置根导航:

UIKit生命周期(AppDelegate)

// AppDelegate.swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let rootNav = NavigationCoordinator.shared.rootNavigationController()
        rootNav.pushViewController(HomeScreenController(), animated: false)
        window?.rootViewController = rootNav
        window?.makeKeyAndVisible()
        return true
    }
}

SwiftUI生命周期(App文件)

// MyApp.swift
import SwiftUI

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            NavigationCoordinator.shared.rootNavigationController().toSwiftUI()
        }
    }
}

// 扩展:将UINavigationController转为SwiftUI View
extension UINavigationController {
    func toSwiftUI() -> UIViewControllerRepresentable {
        VCWrapper(viewController: self)
    }
}

struct VCWrapper: UIViewControllerRepresentable {
    let viewController: UIViewController
    
    func makeUIViewController(context: Context) -> UIViewController { viewController }
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

方案优势

  • 全局统一:所有页面跳转逻辑一致,避免跨框架导航混乱
  • 复用性强:导航栏一次实现,SwiftUI/UIKit页面直接复用
  • 扩展性高:新增页面类型只需在协调器中添加对应跳转方法即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:25:24