Подтвердить что ты не робот

Что вызывает Container View, чтобы сохранить рамку представления своего ребенка в соответствии с ее границами?

Я пытаюсь лучше понять, как Container Views работает в раскадровке. Похоже, что поведение контейнера заставит его подпункт изменить размер, чтобы заполнить контейнер.

storyboard relationships

Я не вижу ограничений, которые объясняют это, и нет упоминания о том, что это за класс. Похоже, какая-то маска раскадровки.

constraints

Я предполагаю, что представление контейнера должно быть подклассом UIView, и у меня будет дикая догадка и предположим, что он называется UIContainerView, но поиск в документации дает только два результата.

search results

Итак, как это работает?

4b9b3361

Ответ 1

Редактор раскадровки (Interface Builder) сохраняет встроенный просмотр frame в виде контейнера bounds во время редактирования. Таким образом, когда раскадровка записывается в файл, сериализованные размеры представлений идентичны. Это происходит независимо от того, включена ли раскадровка в автоматическом макете.

В представлении верхнего уровня каждого контроллера представления в раскадровке также имеется маска для авторезистирования, установленная на UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight, снова независимо от того, включена ли раскадровка в автоматическом макете.

Если включена автоматическая компоновка, каждое представление верхнего уровня имеет translatesAutoresizingMaskToConstraints значение YES. Это отличается от всех потомков этих представлений верхнего уровня. У всех потомков translatesAutoresizingMaskToConstraints установлено значение NO.

Взаимодействие вложения представлено как сегмент класса UIStoryboardEmbedSegue. (Это частный класс, а не открытый API).

Когда UIStoryboardEmbedSegue получает сообщение perform, он загружает представление контроллера представления назначения и добавляет его в качестве подсмотра представления контейнера. Затем он устанавливает встроенный вид autoresizingMask в UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight. Это избыточно, поскольку Interface Builder уже установил его таким образом в раскадровке.

Затем -[UIStoryboardEmbedSegue perform] проверяет встроенный просмотр translatesAutoresizingMaskToConstraints. Это также избыточно, потому что Interface Builder установил его в YES.

Если встроенный просмотр translatesAutoresizingMaskToConstraints равен YES, perform устанавливает встроенный вид frame в представление контейнера bounds. Опять же, избыточный.

Если встроенный просмотр translatesAutoresizingMaskToConstraints равен NO, perform добавляет ограничения H:|[childView]| и V:|[childView]|, тем самым вынуждая встроенный просмотр заполнить представление контейнера. (Да, на самом деле он использует язык визуального формата.) Эта ветка не должна быть достигнута.

Если для представления translatesAutoresizingMaskToConstraints установлено значение YES, автоматический макет автоматически добавляет ограничения типа NSAutoresizingMaskLayoutConstraint и сохраняет их в актуальном состоянии при изменении вида frame. Например, корневой вид окна создается для заполнения окна с помощью ограничений автосохранения:

<NSAutoresizingMaskLayoutConstraint:0x7555d00 h=-&- v=-&- UIView:0x7671780.midX == UIWindow:0x7551010.midX>,
<NSAutoresizingMaskLayoutConstraint:0x7555de0 h=-&- v=-&- UIView:0x7671780.width == UIWindow:0x7551010.width>,
<NSAutoresizingMaskLayoutConstraint:0x7555eb0 h=-&- v=-&- UIView:0x7671780.midY == UIWindow:0x7551010.midY + 10>,
<NSAutoresizingMaskLayoutConstraint:0x7555ef0 h=-&- v=-&- UIView:0x7671780.height == UIWindow:0x7551010.height - 20>

Итак, что-то "заставляет Container View держать свой дочерний ракурс просмотра в соответствии с его границами".

Я понял это, посмотрев файл .storyboard (это удивительно читаемый XML) и посмотрев -[UIStoryboardEmbedSegue perform] в Hopper.

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

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

  • У Apple есть внутренние инструменты, которые генерируют раскадровки по-разному, чем IB.

  • Код для передовой совместимости с будущими версиями IB, которые позволяют представлениям верхнего уровня раскадров иметь разные свойства.

Ответ 2

Настройка тестового проекта и переход по коду дает вам достаточно четкое представление о том, как это реализовано. Вид контейнера - это простой UIView. Как часть процесса loadView контроллера, представление контейнера создается с установкой ограничений в раскадровке. Затем выполняется встроенный контроллер segue. Это создает контроллер дочернего представления, который имеет свой вид, добавленный в качестве подсмотра представления контейнера, и соответствующую настройку ограничений макета, чтобы дочерний вид заполнял контейнер. Это действительно так.