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

如何在UIKit项目中调用SwiftUI自定义组件框架?

在UIKit项目中集成SwiftUI组件框架并在TableView中展示

最初使用UIKit进行开发,后因需求转向SwiftUI。目前拥有一个包含按钮、文本框等自定义组件的SwiftUI框架,已将其添加到UIKit项目并创建了工作区,希望在TableView中逐个展示这些组件,框架中包含ComponentFactory类可根据标识符返回对应组件:

public class ComponentFactory {
    var identifier: String
    public static let shared = ComponentFactory(identifier: "")
    
    public init (identifier: String) {
        self.identifier = identifier
    }
    
    @ViewBuilder public func createView(identifier: String) -> some View {
        switch identifier {
        case "txt":
            TextComponent()
        case "btn":
            ButtonComponent(action: {})
        case "img":
            ImageComponent()
        default:
            Text("Hey, check identifier")
        }
    }
}

核心思路:用UIHostingController桥接SwiftUI与UIKit

UIKit通过UIHostingController可以直接承载SwiftUI视图,这是两者交互的核心工具。我们需要把SwiftUI组件包裹成UIHostingController,再嵌入到UIKit的TableViewCell中。

步骤1:优化ComponentFactory(可选但更合理)

原代码中ComponentFactory的identifier成员变量无实际作用,因为createView方法已接收标识符参数,可简化为:

public class ComponentFactory {
    public static let shared = ComponentFactory()
    
    private init() {} // 私有化初始化,确保单例唯一
    
    @ViewBuilder public func createView(identifier: String) -> some View {
        switch identifier {
        case "txt":
            TextComponent()
        case "btn":
            ButtonComponent(action: { print("Button tapped!") })
        case "img":
            ImageComponent()
        default:
            Text("Hey, check identifier")
        }
    }
}

步骤2:自定义UITableViewCell承载SwiftUI组件

创建自定义Cell,内部嵌入UIHostingController的视图,通过自动布局让其填充整个cell的contentView:

import UIKit
import SwiftUI

class SwiftUIComponentCell: UITableViewCell {
    private var hostingController: UIHostingController<AnyView>?
    
    func configure(with identifier: String) {
        // 移除旧的hosting controller视图
        hostingController?.view.removeFromSuperview()
        hostingController = nil
        
        // 通过工厂创建SwiftUI视图并包裹为AnyView(类型擦除)
        let swiftUIView = ComponentFactory.shared.createView(identifier: identifier)
        hostingController = UIHostingController(rootView: AnyView(swiftUIView))
        
        guard let hostView = hostingController?.view else { return }
        
        // 添加到contentView并设置约束
        contentView.addSubview(hostView)
        hostView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            hostView.topAnchor.constraint(equalTo: contentView.topAnchor),
            hostView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            hostView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            hostView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
    }
}

步骤3:配置TableView的数据源与自适应高度

在ViewController中设置TableView,注册自定义Cell,并处理数据源。开启自动高度计算以适配SwiftUI组件的动态高度:

import UIKit

class ViewController: UIViewController {
    private let tableView = UITableView()
    // 模拟组件标识符列表
    private let componentIdentifiers = ["txt", "btn", "img", "unknown"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTableView()
    }
    
    private func setupTableView() {
        view.addSubview(tableView)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ])
        
        // 注册自定义Cell
        tableView.register(SwiftUIComponentCell.self, forCellReuseIdentifier: "SwiftUIComponentCell")
        // 设置自动高度
        tableView.rowHeight = UITableView.automaticDimension
        tableView.estimatedRowHeight = 100 // 预估高度提升性能
        
        tableView.dataSource = self
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return componentIdentifiers.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "SwiftUIComponentCell", for: indexPath) as! SwiftUIComponentCell
        let identifier = componentIdentifiers[indexPath.row]
        cell.configure(with: identifier)
        return cell
    }
}

注意事项

  • 确保SwiftUI组件框架已正确添加到UIKit项目的工作区,且在target依赖中包含该框架。
  • 若SwiftUI组件有动态高度变化(如可变文本),UIHostingController会自动处理,TableView的automaticDimension会根据实际内容计算高度。
  • 如需在SwiftUI组件中回调UIKit代码,可通过闭包传递(比如ButtonComponent的action参数,在configure时传入UIKit侧逻辑)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 18:45:05