#xcode #macos #cocoa #xcode8 #macos-sierra
#xcode #macos #cocoa #xcode8 #macos-sierra
Вопрос:
Я хочу использовать NSStackView в качестве «плавающего» контейнера для кнопок. т. Е. горизонтальный NSStackView, который действует как своего рода панель инструментов и содержит ряд квадратных кнопок (фиксированного размера). Во время выполнения некоторые кнопки будут динамически отображаться / скрываться, и я хочу, чтобы этот NSStackView динамически регулировал свою ширину в соответствии с видимыми кнопками (плюс интервал, края и т.д.).
Итак, этот NSStackView будет иметь:
- Фиксированная высота
- Динамическая ширина, основанная на его содержимом
- Его точное положение в родительском представлении неизвестно во время разработки
- Ряд кнопок NSButtons с фиксированными размерами
У меня есть файл nib, содержащий NSStackView и его кнопки, которые я загружаю во время выполнения:
Bundle.main.loadNibNamed("ToolbarView", owner: self, topLevelObjects: nil)
toolbarView.detachesHiddenViews = true
toolbarView.setFrameOrigin(NSPoint(x: 100, y: 100))
Я изо всех сил пытаюсь найти точную комбинацию свойств и ограничений, чтобы заставить это поведение работать. Когда я скрываю некоторые кнопки, NSStackView отделяет их, но не сжимает, чтобы соответствовать общей ширине отображаемых кнопок. Я перепробовал все опции NSStackView NSStackViewDistribution
.
Я подозреваю, что мне не хватает некоторых ограничений для выполнения этой работы, но все примеры NSStackView, которые я нахожу, привязывают NSStackView к его супервизору, и я не могу этого сделать, потому что его позиция в родительском представлении задается во время выполнения.
Есть ли какой-либо способ заставить это работать или мне нужно вернуться к ручному вычислению ширины видимых кнопок (что делает использование NSStackView бессмысленным)?
Ответ №1:
Каково значение translatesAutoresizingMaskIntoConstraints
в представлении стека после загрузки его из nib? Если true, то что autoresizingMask
? (по умолчанию должно быть .none).
Если это так, то существуют ограничения маски автоматического изменения размера, которые удерживают на месте происхождение и размер фрейма стекового представления (т. Е. Все, что загружается из кончика).
Лучший способ справиться с этим — установить translatesAutoresizingMaskIntoConstraints
значение false, а затем использовать ограничения для размещения его в родительском представлении во время выполнения.
Комментарии:
1. Если я установлю
translatesAutoresizingMaskIntoConstraints
значение false, мне нужно добавить ограничения вручную, чтобы родительское представление не жаловалось на отсутствующие ограничения. Знаете ли вы, какие ограничения я должен добавить в этом случае для достижения желаемого поведения?2. Это зависит от того, чего именно вы пытаетесь достичь с помощью динамического позиционирования. Но
stackView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: 100).active = true; stackView.topAnchor.constraint(equalTo: parentView.topAnchor, constant: 100).active = true
должно быть моральным эквивалентом источника фрейма, установленного выше. Если эта позиция может измениться позже, вы можете сохранить ссылку на ограничения и изменить ихconstant
свойство.3. Я обнаружил, что изменение маски автоматического изменения размера перед добавлением NSStackView к его родительскому элементу дает мне желаемое поведение с правильной маской. Но, похоже, это работает только на простом родительском NSView. Когда я попытался сделать то же самое для вложенного представления внутри NSSplitView, это не сработало. Похоже, что NSSplitView не учитывает маску автоматического изменения размера, установленную во внутренних представлениях, и изменяет ее внутренне. Я не нашел никакого способа заставить его работать с маской автоматического изменения размера, когда NSStackView вложен в NSSplitView.
Ответ №2:
В дополнение к уже упомянутым translatesAutoresizingMaskIntoConstraints
и ведущим и верхним ограничениям, вы пробовали изменять приоритет охвата представления стека? Используйте значение 1000 (обязательно), чтобы полностью предотвратить расширение представления стека за пределы его содержимого:
stackView.setHuggingPriority(1000, for: .horizontal)
Комментарии:
1. Спасибо. Я пробовал это. Но проблема заключалась в том, что ограничения, созданные из маски автоматического изменения размера, не позволяли NSStackView изменять размер самого себя, поэтому приоритет не помог. Думаю, теперь я более или менее понимаю, в чем была моя проблема (проблемы). (смотрите Мой комментарий к ответу @Taylor).
2. Я думаю, вы здесь упускаете суть. Это намного проще, если забыть о маске автоматического изменения размера и просто делать все с ограничениями. Таким образом, у вас есть только одна система компоновки, о которой нужно подумать. Просто отключите
translatesAutoresizingMaskIntoConstraints
, как только сможете (в идеале, перед вставкой в иерархию представлений), и не прикасайтесь к нему после этого. Просто подумайте, что вы хотели, чтобы маска автоматического изменения размера выполняла, и создайте ограничения для этого.