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

iOS15下UITableViewCell内嵌SwiftUI视图动态高度计算错误问题

iOS15下UITableViewCell嵌入SwiftUI视图复用时高度异常解决方案

问题描述

在UITableViewCell中嵌入SwiftUI视图的实现,在iOS15之前的系统版本运行正常,但在iOS15上滚动UITableView时,初始可见的cell滑出屏幕后,新复用的cell会被添加额外高度,显示异常。
异常效果示意图

问题根因

该异常由iOS15的两处系统变更触发:

  1. UITableView新增sectionHeaderTopPadding属性,默认值为22,会给所有section顶部新增额外空白
  2. UIHostingController的视图如果没有被正确关联到视图控制器层级,其内部自动尺寸计算逻辑会在cell复用时出现偏差,和UITableView的自动高度计算逻辑冲突,产生多余高度

修复方案

1. 适配UITableView iOS15 默认配置

在ViewController的viewDidLoad方法中添加以下代码,关闭默认的section顶部留白:

override func viewDidLoad() {
    super.viewDidLoad()
    // 原有配置保持不变
    tableView?.register(TableViewCell.self, forCellReuseIdentifier: "cell")
    tableView?.rowHeight = UITableView.automaticDimension
    tableView?.estimatedRowHeight = 100
    tableView?.separatorColor = .white
    tableView?.dataSource = self
    // 新增iOS15适配代码
    if #available(iOS 15.0, *) {
        tableView?.sectionHeaderTopPadding = 0
    }
}

2. 优化TableViewCell中UIHostingController的实现

需要持有UIHostingController实例,正确关联控制器生命周期,同时显式设置布局优先级避免约束冲突:

class TableViewCell: UITableViewCell {
    var stackView: UIStackView = {
        let stack = UIStackView(frame: .zero)
        stack.axis = .vertical
        return stack
    }()
    // 持有HostingController实例,避免被提前释放
    private var hosting: UIHostingController<TestView>?

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }
    
    func setupView() {
        contentView.clipsToBounds = true
        contentView.addSubview(stackView)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            stackView.topAnchor.constraint(equalTo: contentView.topAnchor),
            stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
        ])
        let hosting = UIHostingController(rootView: TestView())
        self.hosting = hosting
        guard let hostingView = hosting.view else { return }
        hostingView.translatesAutoresizingMaskIntoConstraints = false
        // 禁用默认安全区域边距适配
        hostingView.insetsLayoutMarginsFromSafeArea = false
        hostingView.backgroundColor = .red
        stackView.addArrangedSubview(hostingView)
        // 显式设置垂直方向的尺寸优先级,避免和UITableView预估高度冲突
        hostingView.setContentHuggingPriority(.required, for: .vertical)
        hostingView.setContentCompressionResistancePriority(.required, for: .vertical)
    }

    // cell加入视图层级时,关联HostingController到父控制器
    override func didMoveToSuperview() {
        super.didMoveToSuperview()
        if let parentVC = self.findViewController(),
           let hosting = hosting,
           hosting.parent == nil {
            parentVC.addChild(hosting)
            hosting.didMove(toParent: parentVC)
        }
    }

    // cell复用时,解绑HostingController的父子关系
    override func prepareForReuse() {
        super.prepareForReuse()
        if let hosting = hosting,
           hosting.parent != nil {
            hosting.willMove(toParent: nil)
            hosting.removeFromParent()
        }
    }
}

// 扩展UIView工具方法,查找当前视图所属的视图控制器
extension UIView {
    func findViewController() -> UIViewController? {
        var nextResponder = self.next
        while let responder = nextResponder {
            if let vc = responder as? UIViewController {
                return vc
            }
            nextResponder = responder.next
        }
        return nil
    }
}

3. 可选兜底适配

如果仍偶现高度异常,可以给SwiftUI视图添加忽略安全区域的修饰符,强制固定尺寸:

struct TestView: View {
    var body: some View {
        Rectangle()
            .fill(Color.green)
            .frame(height: 100)
            .ignoresSafeArea()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 16:45:00