I want 2 labels (say leftLabel, rightLabel) and place them horizontally such that leftLabel stretches and rightLabel just fits single character icon (say, ">"). Thus both labels layout justified. Like this...
This is the code I have -
class StackViewController: UIViewController {
/// Main vertical outer/container stack view that pins its edges to this view in storyboard (i.e. full screen)
@IBOutlet weak private var containerStackView: UIStackView!
private var leftLabel: UILabel = {
let leftLabel = UILabel(frame: .zero)
leftLabel.font = .preferredFont(forTextStyle: .body)
leftLabel.numberOfLines = 0 // no text truncation, allows wrap
leftLabel.backgroundColor = .orange
return leftLabel
}()
private var rightLabel: UILabel = {
let rightLabel = UILabel(frame: .zero)
rightLabel.font = .preferredFont(forTextStyle: .body)
// Set CHCR as high so that label sizes itself to fit the text
rightLabel.setContentHuggingPriority(UILayoutPriorityDefaultHigh, for: .horizontal)
rightLabel.setContentCompressionResistancePriority(UILayoutPriorityDefaultHigh, for: .horizontal)
rightLabel.backgroundColor = .green
return rightLabel
}()
override func viewDidLoad() {
super.viewDidLoad()
prepareAndLoadSubViews()
// Note, the text required to be set in viewDidAppear, not viewDidLoad, otherwise rightLabel stretches to fill!!
leftLabel.text = "This is left label text that may go in multiple lines"
rightLabel.text = ">" // Always a single character
}
/// Dynamically creates a horizontal stack view, with 2 labels, in the container stack view
private func prepareAndLoadSubViews() {
/// Prepare the horizontal label stack view and add the 2 labels
let labelStackView = UIStackView(arrangedSubviews: [leftLabel, rightLabel])
labelStackView.axis = .horizontal
labelStackView.distribution = .fillProportionally
labelStackView.alignment = .top
containerStackView.addArrangedSubview(labelStackView)
containerStackView.addArrangedSubview(UIView())
}
}
Which gives below result (i.e. leftLabel width is 0 in view debugger) -
NOTE: If I move text set code in viewDidAppear then it works fine.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Note, the text required to be set in viewDidAppear, not viewDidLoad, otherwise rightLabel stretches to fill!!
leftLabel.text = "This is left label text that may go in multiple lines"
rightLabel.text = ">" // Always a single character
}
Why? And, can we set content hugging/ compression resistance priorities before viewDidLoad?