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

如何根据文本内容动态设置UITableViewCell中UITextView的高度?

解决UITableViewCell中动态高度UITextView的行高适配问题

你当前的问题主要出在行高计算逻辑错误和Auto Layout约束配置不当这两个点上,咱们一步步来解决:

一、先理清你现有代码的问题

你在heightForRowAt里调用tableView.cellForRow(at: indexPath)是完全错误的——因为系统计算行高的时机,早于单元格的创建/复用时机,这个方法此时返回的cell大概率是nil,所以你的if分支根本不会执行,自然所有行都返回固定的120高度。另外messageView不显示,和你没给它配置完整的垂直约束直接相关。

二、推荐方案:用Auto Layout自动计算行高(最可靠)

这是苹果官方推荐的方式,不需要手动计算行高,只需要做好约束配置和TableView设置:

1. 正确配置messageView的约束

确保你的messageView满足以下条件:

  • 不要给它设置固定高度约束
  • 配置完整的垂直约束链:比如顶部和cell内的其他元素(或contentView顶部)相连,底部和contentView底部相连,同时设置左右边距
  • 必须设置messageView.isScrollEnabled = false(禁止滚动,TextView才会自动根据文本换行并调整自身高度)

示例PostCell的约束配置代码:

class PostCell: UITableViewCell {
    let messageView: UITextView = {
        let tv = UITextView()
        tv.translatesAutoresizingMaskIntoConstraints = false
        tv.font = UIFont.systemFont(ofSize: 17) // 和你实际使用的字体一致
        tv.isScrollEnabled = false // 关键!必须关闭滚动
        tv.textContainerInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) // 可选,调整文本内边距
        return tv
    }()
    
    // 假设你cell里其他元素的高度总和是120,这里用一个占位view模拟
    let topContainerView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .systemBlue
        return view
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupSubviews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupSubviews() {
        contentView.addSubview(topContainerView)
        contentView.addSubview(messageView)
        
        NSLayoutConstraint.activate([
            // 顶部容器固定高度120,对应你的最小高度基础
            topContainerView.topAnchor.constraint(equalTo: contentView.topAnchor),
            topContainerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            topContainerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            topContainerView.heightAnchor.constraint(equalToConstant: 120),
            
            // messageView的约束:顶部接顶部容器,底部接contentView底部,左右留边
            messageView.topAnchor.constraint(equalTo: topContainerView.bottomAnchor, constant: 12),
            messageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
            messageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
            messageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -12)
        ])
    }
}

2. 配置TableView的自动行高

在你的ViewController的viewDidLoad里添加以下代码:

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(PostCell.self, forCellReuseIdentifier: "PostCell")
    
    // 开启自动行高
    tableView.rowHeight = UITableView.automaticDimension
    // 设置一个接近最小行高的估计值,帮助系统优化滚动性能
    tableView.estimatedRowHeight = 140 // 120+24(messageView的上下边距)
}

3. 简化cellForRowAt实现

不需要额外处理高度,只需要给messageView赋值文本即可:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostCell
    let message = yourDataSourceArray[indexPath.row] // 替换成你的数据源
    cell.messageView.text = message
    return cell
}

三、如果一定要手动计算行高(不推荐,但满足你的需求)

如果你坚持要手动计算120 + messageView高度,那应该直接用数据源文本计算,而不是去获取cell:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let baseHeight: CGFloat = 120
    let message = yourDataSourceArray[indexPath.row]
    
    // 计算文本需要的高度:要和messageView的字体、宽度一致
    let textWidth = tableView.bounds.width - 32 // 对应messageView的左右边距16*2
    let textAttributes: [NSAttributedString.Key: Any] = [
        .font: UIFont.systemFont(ofSize: 17)
    ]
    let textSize = message.boundingRect(
        with: CGSize(width: textWidth, height: CGFloat.greatestFiniteMagnitude),
        options: .usesLineFragmentOrigin,
        attributes: textAttributes,
        context: nil
    ).size
    
    // 加上messageView的上下边距(如果有)
    return baseHeight + textSize.height + 24 // 24是示例中messageView的上下边距12*2
}

关键总结

  1. 永远不要在heightForRowAt里调用cellForRow(at:),时机不对会导致拿不到有效cell
  2. Auto Layout自动行高是最稳定的方案,核心是保证messageView的约束完整且无固定高度,同时关闭滚动
  3. 手动计算行高时,必须基于数据源文本和TextView的实际配置(字体、宽度)来计算

内容的提问来源于stack exchange,提问作者K.Wu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:18:28