изменить размер супервизора после динамического изменения субпредставлений с использованием автоопределения

83

Я не могу, ради бога, повесить этот супервизор с изменением размера.

У меня UIView *superview с 4 UILabels. 2 функционируют как заголовки для 2 других.

Содержимое всех 4 динамически поступает из базы данных.

SizeToFitvs SizeThatFits:(CGSize)vs UIView systemLayoutSizeFittingSize:, передавая UILayoutFittingCompressedSizeили UILayoutFittingExpandedSize.

Я использую автоматическое размещение программно и установил высоту супервизора равной или большей фиктивному числу.

где и как использовать эти SizeToFitvs sizeThatFits:(CGSize)vs UIView systemLayoutSizeFittingSize:, передавая либо UILayoutFittingCompressedSizeили UILayoutFittingExpandedSize. Я прочитал много советов здесь, в стеке, но в итоге ничего не нашел.

Мне нужно пересчитать ограничения для супервизора в каком-то конкретном месте. Маби установил высоту как «@ property» в своем классе контроллера, удалил и прочитал ее? Атм Я попытался поставить все везде и еще кое-что. Тем не менее я получаю тот же конечный результат с фиктивной высотой и текстом, плавающим снаружи. Даже после установки clipsToBound на subview.

Я чешу волосы .. помогите

Pedroinpeace
источник
1
Эй, не могли бы вы разместить свой код где-нибудь на pastebin или еще где-нибудь, если бы я мог посмотреть? У меня похожая проблема. Прошла неделя или больше.
esh

Ответы:

104

Если вы используете Auto Layout, вам нужно сделать следующее:

  1. Убедитесь, что вы не добавляете фиксированные ограничения ширины и / или высоты ни к одному из ваших вложенных представлений (в зависимости от того, какие измерения вы хотите динамически изменять). Идея состоит в том, чтобы позволить внутреннему размеру содержимого каждого подпредставления определять высоту подпредставления. UILabels поставляются с 4 автоматическими неявными ограничениями, которые (с приоритетом ниже, чем Required) будут пытаться сохранить рамку метки точного размера, необходимого для размещения всего текста внутри.

  2. Убедитесь, что края каждой метки жестко соединены (с необходимыми ограничениями приоритета) с краями друг друга и их супервизора. Вы должны быть уверены, что если вы представите себе, что одна из меток увеличивается в размере, это заставит другие метки освободить место для нее и, что наиболее важно, вынудить супервизор также расширяться.

  3. Добавляйте ограничения к супервизору только для того, чтобы установить его положение, а не размер (по крайней мере, не для измерений, которые вы хотите динамически изменять). Помните, что если вы правильно установите внутренние ограничения, его размер будет определяться размерами всех вложенных представлений, поскольку его края каким-то образом связаны с их краями.

Вот и все. Вам не нужно вызывать sizeToFitили systemLayoutSizeFittingSize:заставлять это работать, просто загрузите свои представления и установите текст, и все должно быть. Механизм компоновки системы выполнит расчеты для решения ваших ограничений. (Во всяком случае, вам может потребоваться вызвать setNeedsLayoutсупервизор ... но этого не требуется.)

смайлик
источник
Спасибо, смайлик. Поздний ответ, так как я был в середине проекта и не совсем понял то, что вы думаете. Теперь у меня была возможность поработать еще немного с ограничениями программно, и особенно с, constraintsWithVisualFormatи я полностью понимаю вашу точку зрения о растягивании содержащихся подвидов и как бы выталкивании супервизора до его размера :)
Еще
Я согласен с решением, но у меня оно не работает, проверьте stackoverflow.com/questions/34635838/…
Омер
Этот ответ волшебный. Гораздо меньше усилий с моей стороны, чтобы обзоры выглядели хорошо.
Крис
1
Следует отметить, что translatesAutoresizingMaskIntoConstraints = NOесли вы используете xib.
KudoCC
translatesAutoresizingMaskIntoConstraints = NO - ответ на мой случай. Но теперь у контейнерного представления потерян фрейм, и его источник всегда (0,0), я не могу поместить его в желаемое место. stackoverflow.com/questions/45548372/...
Karim
24

Используйте представления контейнера

В следующем примере у меня есть изображение размером 30x30, а UILabel оно меньше, чем содержащее его представление с текстом-заполнителем. Мне нужно, чтобы содержащее представление было как минимум размером с изображение, но оно должно было увеличиваться, чтобы содержать многострочный текст.

В визуальном формате внутренний контейнер выглядит так:

H:|-(15.0)-[image(30.0)]-(15.0)-[label]-(15.0)-|
V:|[image(30.0)]|
V:|[label(>=30.0)]|

Затем установите содержащий представление, чтобы оно соответствовало высоте метки. Теперь содержащий представление будет соответствовать размеру метки.

Как отметил @smileyborg в своем ответе, жесткое подключение содержимого к супервизору сообщает механизму компоновки, что простое представление контейнера должно вызывать его рост.

Желтые прямоугольники выравнивания

Если вы хотите, чтобы желтые прямоугольники выравнивания были добавлены -UIViewShowAlignmentRects YESв список аргументов запуска вашей схемы.

UILabel, который является многострочным

Кэмерон Лоуэлл Палмер
источник
12
-UIViewShowAlignmentRects YES- отличный отзыв!
Ральфонсо
2
В этом случае контейнер должен только подобрать высоту под этикетку. Что, если контейнер должен адаптироваться к сумме высот более чем одного вида?
da Rocha Pires
7

Это стало значительно проще с появлением Stack Views в iOS 9. Используйте представление стека внутри вашего представления, чтобы содержать весь ваш контент с изменяемым размером, а затем просто вызовите

view.setNeedsUpdateConstraints()
view.updateConstraintsIfNeeded()
view.setNeedsLayout()
view.layoutIfNeeded()

после изменения вашего контента. Тогда вы сможете получить новый размер, позвонив по телефону

view.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

если вам когда-нибудь понадобится рассчитать точный размер, необходимый для просмотра.

Джейкоб Рут
источник
2
Я использую StackView и динамически добавляю представления, размер этих представлений не изменяется. @ JacobRuth
Mansuu ....
6

Это почти следует за ответом @smileyborg и содержит конкретный пример.

введите описание изображения здесь

Не буду описывать все ограничения, кроме тех, которые связаны с вычислением высоты UI-объектов.

  1. [Метка] У меток не должно быть фиксированного heightограничения, в этом случае AutoLayout не будет изменять размер меток в соответствии с текстом, поэтому ключевым моментом является установка ограничений по краям. (зеленые стрелки)
  2. [Subview] Шаги 1 и 3 очень легко выполнить, но этот шаг может быть неправильно понят. Как и в случае с метками, для вложенных представлений не должно быть установленных heightограничений. Для всех вложенных представлений должно быть topустановлено ограничение, игнорируя bottomограничение, которое может заставить вас думать, что вызовет исключение неудовлетворенного ограничения во время выполнения, но этого не произойдет, если вы установите bottomограничение для последнего вложенного представления. Если этого не сделать, макет будет разрушен. (красные стрелки)

  3. [Superview] Установите все ограничения так, как вам нужно, но обратите внимание на heightограничение. Присвойте ему случайное значение, но сделайте его необязательным, AutoLayout установит высоту точно так, чтобы соответствовать вложенным представлениям. (синие стрелки)

Это работает отлично, нет необходимости вызывать какие-либо дополнительные методы обновления макета системы.

Стефан
источник
как сделать высоту необязательной .. Я новичок в iOS, поэтому не могу понять это. спасибо
Фейсал Насир