如何在UITableViewCell内部的UIView上添加SwiftUI视图
实现UITableViewCell内嵌SwiftUI视图的方案
核心思路
本质是将
UIHostingController关联的SwiftUI视图添加到cell的contentView上,同时维护UIHostingController的父子控制器关系,保证SwiftUI的生命周期、事件响应、状态更新正常工作。
具体实现步骤
- 自定义UITableViewCell类,内部持有对应的UIHostingController实例
- 在cell的初始化方法中做基础配置,预留数据更新入口
- 在cell赋值数据的方法中绑定SwiftUI视图的数据源,同时将hostingController添加到父视图控制器的子控制器链中
- 在cell复用回调中清理旧的hostingController实例,避免复用错乱和内存泄漏
- 父视图控制器中开启UITableView自动算高适配SwiftUI动态高度
完整代码示例
1. 定义要嵌入的SwiftUI视图
struct CustomSwiftUIView: View { // 接收外部传入的渲染数据 var title: String var subTitle: String var body: some View { VStack(alignment: .leading, spacing: 8) { Text(title) .font(.headline) Text(subTitle) .font(.subheadline) .foregroundColor(.secondary) } .padding(.horizontal, 16) .padding(.vertical, 12) } }
2. 自定义内嵌SwiftUI的UITableViewCell
class SwiftUIEmbeddedTableViewCell: UITableViewCell { // 持有SwiftUI对应的HostingController实例 private var hostingController: UIHostingController<CustomSwiftUIView>? override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) baseSetup() } required init?(coder: NSCoder) { super.init(coder: coder) baseSetup() } private func baseSetup() { contentView.backgroundColor = .clear selectionStyle = .none } // 对外暴露的配置方法,接收渲染数据和父VC引用 func configure(title: String, subTitle: String, parentVC: UIViewController) { // 已创建过hostingController则直接更新根视图,避免重复创建 if let hostingController = hostingController { hostingController.rootView = CustomSwiftUIView(title: title, subTitle: subTitle) } else { let hostVC = UIHostingController(rootView: CustomSwiftUIView(title: title, subTitle: subTitle)) hostVC.view.translatesAutoresizingMaskIntoConstraints = false hostVC.view.backgroundColor = .clear // 关联父子控制器,保证SwiftUI生命周期正常 parentVC.addChild(hostVC) contentView.addSubview(hostVC.view) // 约束铺满cell的contentView NSLayoutConstraint.activate([ hostVC.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), hostVC.view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), hostVC.view.topAnchor.constraint(equalTo: contentView.topAnchor), hostVC.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) ]) hostVC.didMove(toParent: parentVC) self.hostingController = hostVC } } // 复用时清理旧实例,避免错乱和内存泄漏 override func prepareForReuse() { super.prepareForReuse() hostingController?.willMove(toParent: nil) hostingController?.view.removeFromSuperview() hostingController?.removeFromParent() hostingController = nil } }
3. 父视图控制器中调用示例
// 提前注册cell tableView.register(SwiftUIEmbeddedTableViewCell.self, forCellReuseIdentifier: "SwiftUICell") // 开启自动算高适配SwiftUI动态高度 tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 60 // 填近似预估高度即可 // 数据源方法中配置cell func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "SwiftUICell", for: indexPath) as? SwiftUIEmbeddedTableViewCell else { return UITableViewCell() } let item = dataList[indexPath.row] // 你的业务数据源 cell.configure(title: item.title, subTitle: item.subTitle, parentVC: self) return cell }
注意事项
- 必须把
UIHostingController添加到父视图控制器的子控制器链中,否则会出现SwiftUI手势无响应、状态不更新、生命周期异常的问题 - 可以根据业务需求把代码中的
CustomSwiftUIView替换为泛型,实现单个cell兼容任意SwiftUI视图的效果 - 如果你的SwiftUI视图有透明背景,记得设置
UIHostingController的view背景色为clear,避免出现默认白色背景遮挡下层视图
内容的提问来源于stack exchange,提问作者Sadman Samee
相关产品推荐
相关产品推荐

