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

iOS15及以下适配:含SwiftUI View的动态高度UITableViewCell实现

iOS15及以下实现UITableViewCell高度随内部SwiftUI View动态更新的方案

针对iOS15及以下版本,要实现UITableViewCell高度随内部SwiftUI View的动态内容变化同步更新,核心是让UITableView感知到SwiftUI View的尺寸变化,重新计算单元格高度。以下是具体实现步骤和代码示例:

1. 让ViewModel支持内容更新回调

在SwiftUI View的ViewModel中添加回调闭包,当API请求完成、数据更新后触发回调,通知外部内容已变更:

class MyCustomSwiftUIViewModel {
    let productCode: String
    var onContentUpdated: (() -> Void)?
    
    init(productCode: String) {
        self.productCode = productCode
    }
    
    // 模拟API数据请求
    func fetchData() {
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            // 数据加载完成后更新内部状态
            // ...
            
            // 主线程通知外部内容更新
            DispatchQueue.main.async {
                self.onContentUpdated?()
            }
        }
    }
}

2. 改造UITableViewCell,监听内容变化并触发更新

将UIHostingController作为Cell的属性持有(避免局部变量被释放),并在ViewModel的回调中触发布局更新和TableView的行重加载:

class CustomTableViewCell: UITableViewCell {
    private var hostingController: UIHostingController<MyCustomSwiftUIView>?
    
    override func prepareForReuse() {
        super.prepareForReuse()
        // 复用前清理旧的HostingController,避免内存泄漏
        hostingController?.view.removeFromSuperview()
        hostingController?.willMove(toParent: nil)
        hostingController?.removeFromParent()
        hostingController = nil
    }
    
    func configure(with productCode: String) {
        let viewModel = MyCustomSwiftUIViewModel(productCode: productCode)
        let swiftUIView = MyCustomSwiftUIView(viewModel: viewModel)
        let vc = UIHostingController(rootView: swiftUIView)
        hostingController = vc
        
        // 将HostingController的View添加到Cell的contentView并设置约束
        vc.view.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(vc.view)
        NSLayoutConstraint.activate([
            vc.view.topAnchor.constraint(equalTo: contentView.topAnchor),
            vc.view.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            vc.view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            vc.view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
        
        // 将HostingController添加到根控制器,保证生命周期正常
        self.window?.rootViewController?.addChild(vc)
        vc.didMove(toParent: self.window?.rootViewController)
        
        // 监听内容更新,同步Cell高度
        viewModel.onContentUpdated = { [weak self] in
            guard let self = self else { return }
            // 强制布局更新,让SwiftUI View的新尺寸生效
            self.contentView.layoutIfNeeded()
            
            // 找到当前Cell对应的IndexPath,通知TableView重加载该行
            if let tableView = self.superview as? UITableView,
               let indexPath = tableView.indexPath(for: self) {
                tableView.reloadRows(at: [indexPath], with: .automatic)
            }
        }
        
        // 触发API请求
        viewModel.fetchData()
    }
}

3. 配置UITableView支持自动高度

确保TableView开启自动高度计算,并设置合理的预估高度:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    private let tableView = UITableView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTableView()
    }
    
    private func setupTableView() {
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)
        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)
        ])
        
        tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomCell")
        // 开启自动高度计算
        tableView.rowHeight = UITableView.automaticDimension
        // 设置预估高度,优化滚动体验
        tableView.estimatedRowHeight = 200
        
        tableView.dataSource = self
        tableView.delegate = self
    }
    
    // UITableView数据源实现
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell
        cell.configure(with: "\(indexPath.row)")
        return cell
    }
}

关键注意事项

  • 内存泄漏防护:在ViewModel的回调中使用[weak self],避免Cell与ViewModel形成循环引用;复用Cell时务必清理旧的HostingController。
  • 布局强制更新:调用contentView.layoutIfNeeded()确保SwiftUI View的新尺寸被AutoLayout系统识别,为TableView计算正确高度提供依据。
  • 预估高度设置:必须设置estimatedRowHeight,否则UITableView无法正确触发自动高度计算,可能导致高度异常或滚动卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:35:44