В Xcode 5 компания Apple представила новую систему построения интерфейсов приложений для iOS (6+) и MAC OS X (v10.7 +) “Auto Layout” (AL) призванную заменить устаревшую “Springs & Struts” (S&S). Основываясь на задании правил (Constraints) определяющих размер и положение интерфейсных элементов, AL предоставляет значительно более широкие возможности чем S&S. Тем не менее, слабой стороной AL (помимо большей сложности) является работа с переменными наборами элементов. Сама по себе система AL вообще не поддерживает опциональные элементы, но есть способы обойти это ограничение.
Предположим нам нужно показывать карточки пород кошек, в каждой карточке будет название породы, страна происхождения и краткое описание. Создадим новый xib файл для нашей карточки, добавим в корневой view три label’а (не забывая выставить свойство lines = 0) и установим необходимые constraints:
![](https://habrastorage.org/r/w1560/files/e2d/5c0/96d/e2d5c096dd52428c802ceecf39345808.png)
Добавим несколько таких карточек в ScrollView:
![](https://habrastorage.org/r/w1560/files/fe4/dc4/81b/fe4dc481ba9746c9bf671abd085bf7cb.png)
Тут у нас нет опциональных элементов и все выглядит так как должно, но что будет если у нас недостаточно информации? Например, мы не знаем страну происхождения или отсутсвует описание?
![](https://habrastorage.org/r/w1560/files/0bb/a7b/e6c/0bba7be6cd0c4e1698d379a083904817.png)
Очевидно размеры label’ов для отсутствующих данных стали нулевыми, а отступы сверху и снизу просто сложились. Решить данную проблему можно несколькими способами:
Способ первый: удалить неиспользуемые элементы из view при заполнение данных. Вместе с удалением элемента интерфейса удаляются и все связанные с ним constraint’ы. Правда, если просто удалить, например, label страны происхождения пароды, то отступ между названием и описанием будет не определен. Поэтому сначала необходимо добавить дополнительные constraint’ы для случаев удаления каждого из необязательных элементов:
![](https://habrastorage.org/r/w1560/files/8ac/337/218/8ac3372185cb42b285da39e89f1544df.png)
Теперь при заполнении данных достаточно вызвать для пустых label’ов метод
и карточки будут формироваться правильно:
![](https://habrastorage.org/r/w1560/files/617/3cf/1ca/6173cf1ca608449ab92bfeb64c61720c.png)
В этом подходе есть два недостатка:
Чтобы избежать этих недостатков придется пересмотреть структуру нашей карточки:
Добавим constraint’ы:
![](https://habrastorage.org/r/w1560/files/b5d/96c/2c1/b5d96c2c120d41139d7b921161445363.png)
Причем для constraint’ов внутри блоков (отмечены пунктиром) установим значение приоритета равное 750 (High)
Теперь осталось только добавить constraint’ы для высот:
![](https://habrastorage.org/r/w1560/files/9c2/89d/8a9/9c289d8a9c57412db5c6b5503a45ab1a.png)
Способ второй: задать высоту блоков с контентом. Меняя значения X, Y, Z можно ограничивать максимальную высоту каждого блока, таким образом при заполнении карточки в случае отсутствия контента задавать значение высоты блока 0, а в случае если контент есть то любое значение заведомо превышающее максимально возможную высоту блока.
Таким образом мы избежали всех недостатков предыдущего способа: количество необходимых constraint’ов не увеличивается пропорционально количеству опциональных элементов и карточка может быть использована повторно.
Выводы:
Если не требуется повторное использование и количество опциональных элементов невелико то лучше добавить дополнительные constraint’ы и удалять ненужные элементы при заполнении данных. В случае когда либо требуется повторное использование, либо много опциональных элементов стоит разбить интерфейс на блоки и для пустых блоков устанавливать высоту равную 0.
Предположим нам нужно показывать карточки пород кошек, в каждой карточке будет название породы, страна происхождения и краткое описание. Создадим новый xib файл для нашей карточки, добавим в корневой view три label’а (не забывая выставить свойство lines = 0) и установим необходимые constraints:
![](https://habrastorage.org/files/e2d/5c0/96d/e2d5c096dd52428c802ceecf39345808.png)
Добавим несколько таких карточек в ScrollView:
![](https://habrastorage.org/files/fe4/dc4/81b/fe4dc481ba9746c9bf671abd085bf7cb.png)
Тут у нас нет опциональных элементов и все выглядит так как должно, но что будет если у нас недостаточно информации? Например, мы не знаем страну происхождения или отсутсвует описание?
![](https://habrastorage.org/files/0bb/a7b/e6c/0bba7be6cd0c4e1698d379a083904817.png)
Очевидно размеры label’ов для отсутствующих данных стали нулевыми, а отступы сверху и снизу просто сложились. Решить данную проблему можно несколькими способами:
Способ первый: удалить неиспользуемые элементы из view при заполнение данных. Вместе с удалением элемента интерфейса удаляются и все связанные с ним constraint’ы. Правда, если просто удалить, например, label страны происхождения пароды, то отступ между названием и описанием будет не определен. Поэтому сначала необходимо добавить дополнительные constraint’ы для случаев удаления каждого из необязательных элементов:
![](https://habrastorage.org/files/e26/57d/9ab/e2657d9ab9a5452e9747dd480a3f6823.png)
![](https://habrastorage.org/files/7b4/c10/1b3/7b4c101b3ae54c628b39ce5147de44b7.png)
![](https://habrastorage.org/files/8ac/337/218/8ac3372185cb42b285da39e89f1544df.png)
Теперь при заполнении данных достаточно вызвать для пустых label’ов метод
- (void)removeFromSuperview
и карточки будут формироваться правильно:
![](https://habrastorage.org/files/617/3cf/1ca/6173cf1ca608449ab92bfeb64c61720c.png)
В этом подходе есть два недостатка:
- Требуется вводить много дополнительных constraint’ов (и их число будет расти с увеличением числа опциональных эелементов)
- Поскольку label’ы удаляются, однажды заполненную карточку нельзя использовать повторно, т.к. нет гарантии что наборы данных совпадут. На первый взгляд это может показаться несущественным, всегда ведь можно создать новую карточку. Но, если нам необходимо показать наши карточки не в ScrollView, а в CollectionView который реализует паттерн “Объектный пул” карточки должны иметь возможность повторного использования.
Чтобы избежать этих недостатков придется пересмотреть структуру нашей карточки:
- Сверху и снизу добавим два view фиксированной высоты они будут служить для задания отступов от краев
- Заключим каждый label в view.
Добавим constraint’ы:
![](https://habrastorage.org/files/b5d/96c/2c1/b5d96c2c120d41139d7b921161445363.png)
Причем для constraint’ов внутри блоков (отмечены пунктиром) установим значение приоритета равное 750 (High)
Теперь осталось только добавить constraint’ы для высот:
![](https://habrastorage.org/files/9c2/89d/8a9/9c289d8a9c57412db5c6b5503a45ab1a.png)
Способ второй: задать высоту блоков с контентом. Меняя значения X, Y, Z можно ограничивать максимальную высоту каждого блока, таким образом при заполнении карточки в случае отсутствия контента задавать значение высоты блока 0, а в случае если контент есть то любое значение заведомо превышающее максимально возможную высоту блока.
Таким образом мы избежали всех недостатков предыдущего способа: количество необходимых constraint’ов не увеличивается пропорционально количеству опциональных элементов и карточка может быть использована повторно.
Выводы:
Если не требуется повторное использование и количество опциональных элементов невелико то лучше добавить дополнительные constraint’ы и удалять ненужные элементы при заполнении данных. В случае когда либо требуется повторное использование, либо много опциональных элементов стоит разбить интерфейс на блоки и для пустых блоков устанавливать высоту равную 0.