如何动态调整UITableViewCell内UILabel高度适配内容行数
问题说明
在UITableView的自定义Cell中,垂直StackView内numberOfLines = 2的UILabel在仅显示1行文本时出现纵向截断,无法根据实际文本行数动态调整高度。已尝试调整StackView分布模式、添加间距、移除StackView单独约束均未完全解决问题。
附原有实现代码:
struct Data { var type, name: String } class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { var data = [Data]() override func viewDidLoad() { super.viewDidLoad() setupView() } lazy var tableView: UITableView = { let tableView = UITableView() tableView.delegate = self tableView.dataSource = self tableView.register(CustomCell.self, forCellReuseIdentifier: "cell") tableView.backgroundColor = .white tableView.separatorStyle = .none return tableView }() func setupView() { data = [ Data(type: "Breakfast", name: "Poached Egg & Avocado Toast with Sliced Cherry Tomatoes"), Data(type: "Lunch", name: "Poached Egg & Avocado Toast") ] view.backgroundColor = .white view.addSubview(tableView) tableView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ tableView.centerXAnchor.constraint(equalTo: view.centerXAnchor), tableView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.9), tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell let data = data[indexPath.row] cell.configure(with: data) cell.backgroundColor = .white return cell } } class CustomCell: UITableViewCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupView() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 0, left: 0, bottom: 20, right: 0)) } lazy var typeLabel: UILabel = { let label = UILabel() label.font = UIFont.systemFont(ofSize: 25, weight: .bold) label.translatesAutoresizingMaskIntoConstraints = false return label }() lazy var nameLabel: UILabel = { let label = UILabel() label.font = UIFont.systemFont(ofSize: 20) label.numberOfLines = 2 label.lineBreakMode = .byWordWrapping label.translatesAutoresizingMaskIntoConstraints = false return label }() lazy var titleStack: UIStackView = { let stack = UIStackView(arrangedSubviews: [typeLabel, nameLabel]) stack.axis = .vertical stack.distribution = .fillProportionally stack.translatesAutoresizingMaskIntoConstraints = false return stack }() lazy var iv: UIImageView = { let iv = UIImageView() iv.contentMode = .scaleAspectFit iv.translatesAutoresizingMaskIntoConstraints = false iv.backgroundColor = .systemMint return iv }() func configure(with mealInfo: Data) { typeLabel.text = mealInfo.type.capitalized nameLabel.text = mealInfo.name iv.image = UIImage(systemName: "star") } func setupView() { contentView.backgroundColor = .systemPurple contentView.addSubview(titleStack) contentView.addSubview(iv) NSLayoutConstraint.activate([ titleStack.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), titleStack.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor, constant: 10), titleStack.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.9) ]) NSLayoutConstraint.activate([ iv.topAnchor.constraint(equalTo: titleStack.bottomAnchor, constant: 10), iv.leftAnchor.constraint(equalTo: titleStack.leftAnchor), iv.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.55), iv.heightAnchor.constraint(equalTo: iv.widthAnchor, multiplier: 0.6), iv.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10) ]) } }
问题根因
显示异常来自三个配置错误:
- 垂直StackView使用了
fillProportionally分布模式,该模式会按照子视图的固有尺寸比例强制分配高度,当nameLabel仅1行文本时,固有高度被比例规则压缩,导致文本截断 - 未开启UITableView自动行高能力,AutoLayout无法根据内容动态计算Cell高度
- 在
layoutSubviews中手动修改contentView的frame,破坏了AutoLayout的尺寸计算链路
解决方案
按以下步骤修改配置即可实现标签高度动态适配:
- 修正StackView配置:将
titleStack的distribution属性从fillProportionally改为.fill,该模式会自动尊重每个子视图的固有内容高度,不会强行压缩单行文本的标签。可按需设置stack.spacing = 8控制两个标签的垂直间距,不需要给两个Label额外添加高度约束,设置了numberOfLines = 2的UILabel会自动根据文本内容返回正确的固有高度。 - 开启TableView自动行高:在tableView初始化闭包中添加两行配置,让系统自动根据约束计算行高:
tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 150 // 填入接近实际行高的估算值即可 - 移除破坏布局的代码:删除
layoutSubviews中手动修改contentView frame的逻辑,需要Cell底部间距时,直接调整iv的bottom约束常量即可,比如将原约束的constant: -10改为constant: -30即可实现和原有逻辑一致的底部边距,不会干扰AutoLayout计算。
修改完成后,垂直方向约束链完全闭合(StackView顶部接contentView顶部 -> StackView底部接图片顶部 -> 图片底部接contentView底部),系统会自动根据nameLabel的实际文本行数(1行/2行)计算整个Cell的正确高度,不会再出现文本截断问题。
内容的提问来源于stack exchange,提问作者Nadia Siddiqah
相关产品推荐
相关产品推荐

