やりたいこと
- table タグを使ってできるレイアウトのようなもの
- 左のラベルは右寄せ。それぞれの幅は一番幅が長いものに合わせる
- 右のラベルは複数行入る。縦方向のレイアウトはこちらで決まる
実現方法
この要件だと UIStackView だけだと実現できなかったので、AutoLayout でゴリッとやったらできた
(Cartography と Then を使っているけど雰囲気は伝わるはず……)
let content: [(heading: String, body: String)] = [
("いち: ", "改行\nする\nテキスト"),
("に: ", "普通のテキスト"),
("さぁん: ", "長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト")
]
let spacing = CGFloat(4)
var prev: (heading: UIView, body: UIView)?
content.forEach { heading, body in
let headingLabel = UILabel().then {
$0.text = heading
table.addSubview($0)
}
let bodyLabel = UILabel().then {
$0.numberOfLines = 0
$0.text = body
table.addSubview($0)
}
if let (prevHeading, prevBody) = prev {
constrain(headingLabel, bodyLabel, prevHeading, prevBody) { headingLabel, bodyLabel, prevHeading, prevBody in
headingLabel.leading >= headingLabel.sv.leading
headingLabel.top == bodyLabel.top
headingLabel.trailing == prevHeading.trailing
bodyLabel.leading == headingLabel.trailing
bodyLabel.trailing == bodyLabel.sv.trailing
bodyLabel.top == prevBody.bottom + spacing
}
} else {
constrain(headingLabel, bodyLabel) { headingLabel, bodyLabel in
headingLabel.leading >= headingLabel.sv.leading
headingLabel.top == bodyLabel.top
bodyLabel.leading == headingLabel.trailing
bodyLabel.trailing == bodyLabel.sv.trailing
bodyLabel.top == bodyLabel.sv.top
}
}
prev = (headingLabel, bodyLabel)
}
if let (_, prevBody) = prev {
constrain(prevBody) { prevBody in
prevBody.bottom == prevBody.sv.bottom
}
}
みどころ
-
headingLabel.leading >= headingLabel.sv.leading
と定義している - 横方向は heading が、縦方向は body が決めているので錯綜感がある
misc
他に良い方法あれば教えてください
(左のラベルが固定だったら NSMutableParagraphStyle#headIndent を使うことで、単一の UILabel で実現できるのだけれども)