#swift #autolayout #uistackview
#swift #автозаполнение #uistackview
Вопрос:
Я хочу создать нижнюю панель чата со следующим содержимым в горизонтальном UIStackView
:
- a
UITextField
с левой стороны, занимая все доступное пространство - метка справа с фиксированным размером (внутренний размер содержимого по умолчанию)
Вот мой код:
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
])
С помощью этого кода метка увеличивает свой размер и заполняет все доступное пространство справа, а текстовое поле не отображается (инспектор говорит width = 0); прямо противоположно тому, что я хочу.
Я не понимаю, почему это не работает, потому что я явно настроил его так, чтобы он не расширял метку с помощью:
label.setContentHuggingPriority(.defaultLow, for: .horizontal)
и вместо этого для расширения текстового поля с:
messageTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
Что я здесь пропустил? Я прочитал много ответов SO, документацию Apple и следил за различными учебными пособиями и видео, но я не могу добиться этой, казалось бы, простой вещи.
Комментарии:
1. Пытались ли вы оставить значения по умолчанию для представления стека, закомментировав sv.distribution = .fill и sv.alignment = .center? По умолчанию должно быть как ‘заполнить’
2. Просто попробовал, но, как вы указали, это значения по умолчанию, поэтому это не устраняет проблему :/
Ответ №1:
У вас все наоборот…
Настройка Content Hugging Priority
означает» контролировать, как этот элемент охватывает его содержимое.
Итак, в качестве примера, если у вас есть a UILabel
, в котором есть только буква «A», высокий приоритет охвата содержимого сохранит ширину метки только до этой единственной буквы.
Итак, с этими двумя строками:
label.setContentHuggingPriority(.defaultLow, for: .horizontal)
messageTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
вы указали автоматическую компоновку:
сохраняйте messageTextField
только ширину текста и разрешайте label
растягивать его шире, чем текст
То, что вы хотите, это:
// don't let label stretch at all
label.setContentHuggingPriority(.required, for: .horizontal)
// let message text field stretch if needed
messageTextField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
Затем представление стека растянет текстовое поле, чтобы заполнить доступное пространство.
Комментарии:
1. Вот и все, большое вам спасибо! Я не являюсь носителем английского языка, я думал, что слово «объятие» означает «огромный», как «отличный», отсюда и мое замешательство!
Ответ №2:
Я быстро попробовал Xcode 12.3 на симуляторе (iPhone 12)
и оставление значений по умолчанию для stackview и обнимания содержимого сработало для меня:
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),
])
}
Это результат:
Комментарии:
1. Спасибо за ваш ответ, Лука. Это работает, но отладчик компоновки сообщает, что оба упорядоченных подвида имеют неоднозначный размер (ширина и горизонтальное положение). Это похоже на восстановление поведения UIStackView в амбициозной ситуации. Я имею в виду, что, если бы у меня было 4 представления (я хочу добавить несколько кнопок слева), как указать, чтобы одно из представлений растягивалось, а другие сжимались?