Reputation: 1207
I want to create a chat bottom bar with the following content, in a horizontal UIStackView
:
UITextField
on the left side, taking all the available spaceHere is my code:
let messageTextField = UITextField()
messageTextField.translatesAutoresizingMaskIntoConstraints = false
messageTextField.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
messageTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "SEND"
label.setContentHuggingPriority(.defaultLow, for: .horizontal)
label.setContentCompressionResistancePriority(.required, for: .horizontal)
label.textColor = .red
let sv = UIStackView()
sv.axis = .horizontal
sv.distribution = .fill
sv.alignment = .center
sv.translatesAutoresizingMaskIntoConstraints = false
// constraint the stack view to the bottomBar view
bottomBar.addSubview(sv)
NSLayoutConstraint.activate([
sv.leadingAnchor.constraint(equalTo: bottomBar.leadingAnchor, constant: 20),
sv.trailingAnchor.constraint(equalTo: bottomBar.trailingAnchor, constant: -20),
sv.bottomAnchor.constraint(equalTo: bottomBar.bottomAnchor, constant: -8),
sv.topAnchor.constraint(equalTo: bottomBar.topAnchor, constant: 8)
])
sv.addArrangedSubview(messageTextField)
sv.addArrangedSubview(label)
NSLayoutConstraint.activate([
messageTextField.heightAnchor.constraint(equalTo:sv.heightAnchor),
// I didn't put any width constraint for textField because it make no sense, as I want it to take all the available space on the right
])
With this code, the label is expanding its size and filling all the available space on the right, and the text field is not showing (inspector says width = 0); exactly the opposite of what I want.
I don't understand why it doesn't work because I explicitly configured it so it does not expand the label with:
label.setContentHuggingPriority(.defaultLow, for: .horizontal)
and instead to expand the text field with:
messageTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
What did I miss here? I have read through many SO answers, Apple documentation, and followed various tutorials and videos, but I'm not able to achieve this seemingly simple thing.
Upvotes: 0
Views: 1266
Reputation: 77691
You have it backwards...
Setting Content Hugging Priority
means" control how this element hugs its content.
So, as an example, if you have a UILabel
with only the letter "A" in it, a High content hugging priority will keep the label only as wide as that single letter.
So with these two lines:
label.setContentHuggingPriority(.defaultLow, for: .horizontal)
messageTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
you've told auto-layout:
keep messageTextField
only as wide as its text, and allow label
to stretch wider than its text
What you want is:
// don't let label stretch at all
label.setContentHuggingPriority(.required, for: .horizontal)
// let message text field stretch if needed
messageTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
The stack view will then stretch the text field to fill the available space.
Upvotes: 1
Reputation: 3467
I tried quickly on Xcode 12.3 on Simulator (iPhone 12 )
and leaving the default values to the stackview and the content hugging, worked for me:
override func viewDidLoad() {
super.viewDidLoad()
// Just added a view anchored to the bottom of the view controller for the purpose of the test
let bottomBar = UIView()
bottomBar.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(bottomBar)
bottomBar.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
bottomBar.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
bottomBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
bottomBar.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
bottomBar.backgroundColor = .yellow
let messageTextField = UITextField()
messageTextField.translatesAutoresizingMaskIntoConstraints = false
messageTextField.backgroundColor = .cyan
// LEAVING DEFAULTS
//messageTextField.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
//messageTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "SEND"
// LEAVING DEFAULTS
//label.setContentHuggingPriority(.defaultLow, for: .horizontal)
//label.setContentCompressionResistancePriority(.required, for: .horizontal)
label.textColor = .red
let sv = UIStackView()
sv.axis = .horizontal
// LEAVING DEFAULTS
//sv.distribution = .fill
//sv.alignment = .center
sv.translatesAutoresizingMaskIntoConstraints = false
// constraint the stack view to the bottomBar view
bottomBar.addSubview(sv)
NSLayoutConstraint.activate([
sv.leadingAnchor.constraint(equalTo: bottomBar.leadingAnchor, constant: 20),
sv.trailingAnchor.constraint(equalTo: bottomBar.trailingAnchor, constant: -20),
sv.bottomAnchor.constraint(equalTo: bottomBar.bottomAnchor, constant: -8),
sv.topAnchor.constraint(equalTo: bottomBar.topAnchor, constant: 8)
])
sv.addArrangedSubview(messageTextField)
sv.addArrangedSubview(label)
NSLayoutConstraint.activate([
messageTextField.heightAnchor.constraint(equalTo:sv.heightAnchor),
])
}
This is the outcome:
Upvotes: 0