如何在TableViewCell中水平布局两个UILabels实现自适应与剩余空间分配?
实现TableViewCell中左右UILabel的自适应截断布局需求
嘿,这个布局需求我之前做过好多次了,其实核心就是利用Auto Layout的**内容拥抱优先级(Content Hugging Priority)和内容压缩抵抗优先级(Content Compression Resistance Priority)**来控制两个标签的布局优先级,再配合截断模式就能搞定。下面一步步来:
1. 基础约束设置(Storyboard/Xib方式)
先给两个标签拖好基本约束:
- 左侧标签:
- 绑定
Leading到cell的contentView(留个合适的边距,比如16pt) - 绑定
Top和Bottom到contentView(边距比如8pt,或者直接用Size Inspector里的「Arrange > Fill Container Vertically」,这个选项会自动帮你添加上下约束,让标签垂直方向填满cell的内容区域) - 绑定
Trailing到右侧标签的Leading(留个间距,比如8pt)
- 绑定
- 右侧标签:
- 绑定
Trailing到contentView(边距16pt) - 同样绑定
Top和Bottom到contentView,或者用「Fill Container Vertically」快速设置
- 绑定
2. 关键优先级调整
这一步是核心,决定了谁被截断谁完整保留:
- 选中左侧标签,在Size Inspector里找到Content Hugging Priority,把水平方向(Horizontal)的优先级设为
251(默认低优先级);再找到Content Compression Resistance Priority,水平方向设为749(比右侧低) - 选中右侧标签,把水平方向的Content Hugging Priority设为
252(比左侧高),Content Compression Resistance Priority设为750(比左侧高)
简单说就是:让右侧标签更“抱紧”自己的内容,更抗拒被压缩;左侧标签则愿意被压缩,这样当总宽度超过cell时,左侧会被截断,右侧保持完整。
3. 截断模式设置
给左侧标签开启截断:
- 在Attributes Inspector里,找到Line Break选项,选择「Truncate Tail」(尾部截断),这样内容过长时会自动显示省略号
关于「Arrange > Fill Container Vertically」的说明
这个选项就是个快捷操作,帮你一键添加Top和Bottom约束到父容器(也就是contentView),不用手动拖约束。开启后,标签会在垂直方向填满cell的内容区域,同时如果标签的内容高度变化,cell的高度也会自适应(前提是你给cell设置了自动高度,比如tableView.rowHeight = UITableView.automaticDimension)。
代码实现方式(如果不用Storyboard)
要是你用纯代码布局,参考下面的示例:
// 先创建两个标签并添加到contentView let leftLabel = UILabel() leftLabel.text = "这是左侧很长很长可能会被截断的文本内容" leftLabel.lineBreakMode = .byTruncatingTail leftLabel.translatesAutoresizingMaskIntoConstraints = false let rightLabel = UILabel() rightLabel.text = "右侧固定内容" rightLabel.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(leftLabel) contentView.addSubview(rightLabel) // 设置约束 NSLayoutConstraint.activate([ // 左侧标签约束 leftLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), leftLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), leftLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8), leftLabel.trailingAnchor.constraint(equalTo: rightLabel.leadingAnchor, constant: -8), // 右侧标签约束 rightLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), rightLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), rightLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8) ]) // 设置优先级 leftLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) leftLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) rightLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) rightLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
这样设置完,就能完美实现你要的效果:右侧标签占自身所需宽度,左侧占剩余空间;总宽度超了的话,左侧自动截断,右侧完整显示,各自对齐左右侧。
内容的提问来源于stack exchange,提问作者Nathan Van Dyken
相关产品推荐
相关产品推荐

