如何通过代码实现基于内容自动调整UITableViewCell高度
兄弟,你猜的没错!问题确实出在自定义Cell里用frame布局而没有给contentView和wrapper添加正确的Auto Layout约束——UITableView的UITableViewAutomaticDimension依赖Auto Layout来计算行高,纯frame布局的话,TableView根本不知道你的Cell实际高度是多少,自然会保持固定行高。
下面一步步帮你解决问题:
第一步:把自定义Cell的Frame布局改成Auto Layout
你现在的AiMessageCell用硬编码frame的方式布局,这会导致TableView无法自动计算Cell高度。咱们把所有子视图换成Auto Layout约束,具体操作如下:
- 给所有子视图关闭
translatesAutoresizingMaskIntoConstraints(告诉系统不要自动生成默认约束,改用我们手动添加的约束) - 给wrapper视图添加和contentView的绑定约束,让wrapper的上下左右和contentView关联,这样contentView的高度会由wrapper的高度决定
- 依次给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里的关键设置
- 必须设置
estimatedRowHeight——这是UITableViewAutomaticDimension生效的前提,TableView需要一个预估高度来先渲染,再调整为实际高度 - 在
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
相关产品推荐
相关产品推荐

