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

如何通过代码实现基于内容自动调整UITableViewCell高度

兄弟,你猜的没错!问题确实出在自定义Cell里用frame布局而没有给contentView和wrapper添加正确的Auto Layout约束——UITableView的UITableViewAutomaticDimension依赖Auto Layout来计算行高,纯frame布局的话,TableView根本不知道你的Cell实际高度是多少,自然会保持固定行高。

下面一步步帮你解决问题:

第一步:把自定义Cell的Frame布局改成Auto Layout

你现在的AiMessageCell用硬编码frame的方式布局,这会导致TableView无法自动计算Cell高度。咱们把所有子视图换成Auto Layout约束,具体操作如下:

  1. 给所有子视图关闭translatesAutoresizingMaskIntoConstraints(告诉系统不要自动生成默认约束,改用我们手动添加的约束)
  2. 给wrapper视图添加和contentView的绑定约束,让wrapper的上下左右和contentView关联,这样contentView的高度会由wrapper的高度决定
  3. 依次给avatar、balloon、message添加约束,确保它们的位置和大小能被系统正确计算

修改后的AiMessageCell代码:

class AiMessageCell: UITableViewCell, NSLayoutManagerDelegate {
    private let wrapper = UIView()
    private let balloon = UIView()
    private let message = UITextView()
    private let avatar = UIImageView(image: UIImage(named: "avatar"))

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupSubviews()
        setupConstraints()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // 给外部提供设置文本的方法
    func configure(with text: String) {
        message.text = text
    }
    
    private func setupSubviews() {
        // 关闭自动约束生成
        [wrapper, balloon, message, avatar].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
        }
        
        // 设置视图样式
        balloon.layer.cornerRadius = 10
        balloon.backgroundColor = UIColor(red: 240/255.0, green: 240/255.0, blue: 240/255.0, alpha: 1.0)
        
        message.font = UIFont.systemFont(ofSize: 16)
        message.isEditable = false
        message.isScrollEnabled = false
        message.isSelectable = false
        message.backgroundColor = .clear
        message.layoutManager.delegate = self
        
        avatar.clipsToBounds = true
        avatar.layer.cornerRadius = 15
        
        // 构建视图层级
        contentView.addSubview(wrapper)
        wrapper.addSubview(balloon)
        wrapper.addSubview(avatar)
        balloon.addSubview(message)
        
        // 保留背景色用于调试
        wrapper.backgroundColor = .purple
        contentView.backgroundColor = .green
    }
    
    private func setupConstraints() {
        NSLayoutConstraint.activate([
            // Wrapper和contentView绑定,上下左右留10间距(可按需调整)
            wrapper.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
            wrapper.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10),
            wrapper.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
            wrapper.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
            
            // Avatar约束:左对齐wrapper,底部对齐wrapper,大小30x30
            avatar.leadingAnchor.constraint(equalTo: wrapper.leadingAnchor),
            avatar.bottomAnchor.constraint(equalTo: wrapper.bottomAnchor),
            avatar.widthAnchor.constraint(equalToConstant: 30),
            avatar.heightAnchor.constraint(equalToConstant: 30),
            
            // Balloon约束:左距avatar10,上下对齐wrapper,右对齐wrapper
            balloon.leadingAnchor.constraint(equalTo: avatar.trailingAnchor, constant: 10),
            balloon.topAnchor.constraint(equalTo: wrapper.topAnchor),
            balloon.bottomAnchor.constraint(equalTo: wrapper.bottomAnchor),
            balloon.trailingAnchor.constraint(equalTo: wrapper.trailingAnchor),
            
            // Message约束:和balloon四边留10间距,高度由文本内容撑开
            message.topAnchor.constraint(equalTo: balloon.topAnchor, constant: 10),
            message.bottomAnchor.constraint(equalTo: balloon.bottomAnchor, constant: -10),
            message.leadingAnchor.constraint(equalTo: balloon.leadingAnchor, constant: 10),
            message.trailingAnchor.constraint(equalTo: balloon.trailingAnchor, constant: -10)
        ])
    }
    
    func layoutManager(_ layoutManager: NSLayoutManager, lineSpacingAfterGlyphAt glyphIndex: Int, withProposedLineFragmentRect rect: CGRect) -> CGFloat {
        return 5
    }
}

第二步:修复ViewController里的关键设置

  1. 必须设置estimatedRowHeight——这是UITableViewAutomaticDimension生效的前提,TableView需要一个预估高度来先渲染,再调整为实际高度
  2. 在cellForRowAt里把文本传给Cell的configure方法,让Cell显示对应内容

修改后的ViewController代码片段:

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 设置预估行高,值可以给个合理的默认值
    tableView.estimatedRowHeight = 100
    tableView.rowHeight = UITableViewAutomaticDimension
    
    tableView.register(AiMessageCell.self, forCellReuseIdentifier: "AiMessageCell")
    tableView.register(UserMessageCell.self, forCellReuseIdentifier: "UserMessageCell")
    tableView.register(UserSelectionCell.self, forCellReuseIdentifier: "UserSelectionCell")
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "AiMessageCell") as! AiMessageCell
    // 传递文本给Cell
    cell.configure(with: rows[indexPath.row])
    return cell
}

核心要点总结

  • UITableViewAutomaticDimension仅在Cell使用Auto Layout约束时生效,纯frame布局无法让TableView获取Cell实际高度
  • 必须给Cell的contentView和最外层wrapper设置上下约束,确保contentView的高度能被内部内容撑开
  • estimatedRowHeight是必选项,否则TableView可能仍会使用默认行高

这样改完之后,你的TableView行高应该就能跟着消息内容自动变化了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:35:43