AutoLayout. Часть вторая.

Всем привет! Я тут перевел одну интересную статью для вас. Приятного чтения!

Оригинальная статья тут.

UIStackView в iOS: Знакомство со Stack Views

Вам когда-либо надо было добавить или удалить views из view во время работы приложения и откорректировать структуру views рядом с ним? Может вы корректировали некоторые constraints или использовали сторонние библиотеки для этой работы. Возможно, это было что-то не во время работы приложения, но одна новая view, которую вы хотели бы вставить между другими views в вашем storyboards.

В этих случаях, вам нужно изменить несколько constraints. Вы можете удалить все constraints в этой области и добавлять их снова и снова.

UIStackView упрощает такие задачи. Вы можете легко расположить несколько views по горизонтали или по вертикали, внутри stack view, и настроить его таким образом, чтобы views автоматически корректировались в доступном пространстве используя свойства такие как alignment, distribution и spacing. Наслаждайтесь! :]

 

Примечание: В этом уроке используются базовые знания о Auto Layout. Если вы новенький в этом, то вам нужно обратить внимание на этот урок.

Начнём

Начнем с загрузки проекта с материалами используя кнопку Download Materials в начале или в конце этого урока. Запустим стартовый проект в Xcode используя iPhone 8 Simulator. Вы увидите следующее:

Это Vacation Spots приложение. Оно предлагает список мест, чтобы уехать куда подальше. Прежде чем куда-то уехать, нужно решить несколько проблем с этим приложением, используя Stack Views.

Исследуем Vacation Spots

Перейдем к окну информации по Лондону нажав на London. На первый взгляд, окно выглядит хорошо, но у него есть несколько проблем:

  1. Посмотрите на строку с кнопками внизу view. Они не адаптировались под ширину экрана, потому что между ними фиксированное расстояние. Чтобы лучше увидеть проблему, смените положение симулятора на альбомное, нажав Command-Left arrow.

 

2. Нажмите Hide напротив WEATHER. Это скроет текст. Но не переместит раздел под ним, оставляя пустое место.

 

3. Порядок разделов тоже нуждается в улучшении. Было бы более логично, если бы WHAT TO SEE появлялось после WHY VISIT вместо того, чтобы расположить раздел weather между ними.

 

4. Нижняя строка с кнопками близко к нижней границе view в альбомном режиме. Это будет выглядеть лучше, если мы уменьшим расстояние между разделами – но только в альбомном режиме.

Теперь, когда у нас есть идеи для улучшения, мы будем их реализовывать – настало время погрузиться в проект. Откройте Main.storyboard. Он откроется с изначальным видом устройства. Убедитесь что у вас отображается iPhone 8 как выбранное устройство.

 

Это не даст никаких бонусов во время работы приложения, но поможет вам увидеть как экраны должны выглядеть на этом устройстве. Вы можете изменить выбранное устройство в любое время нажав на другую иконку. (Наведя курсор на иконку соответствующего устройства).

 

Примечание: Если вы уменьшите ширину блока Interface Builder это привет к изменению интерфейса для смены устройства. Список устройств свернется в Device dropdown:
при нажатии, раскроется список доспупных устройств, расположенных по вертикали:

Теперь внимательно посмотрим на Spot Info View Controller:

Вы догадываетесь Что это за цвета ?

У labels и buttons есть цвет фона, который не показывается во время выполнения работы приложения. В storyboard, они наглядно показывают как меняются различные свойства stack view влияя на frames внутренних views.

Если вы захотите увидеть цвет фона в запущенном приложении, в любой момент вы можете временно закомментировать следующие строки во viewDidLoad() внутри SpotInfoViewController.

// Clear background colors from labels and buttons
for view in backgroundColoredViews {
  view.backgroundColor = UIColor.clear
}

Любой привязанный label имеет placeholder, который совпадает с наименованием привязки. Благодаря этому можно легко сказать какие labels будут обновляться во время работы приложения. Например, label с текстом <whyVisitLabel> привязан к:

@IBOutlet var whyVisitLabel: UILabel!

Пришло время начинать!

Ваш первый Stack View

Во-первых, вы должны зафиксировать расстояние между кнопками на нижней строчке. Stack view может распределить свои subviews вдоль своей оси в различных формах. Один из способов – установить одинаковое расстояние между view.

К счастью, внедрение существующих views в stack view это проще простого. Во-первых, выберите все кнопки внизу Spot Info View Controller нажав на одну, потом с помощью клавиши Command нажмите на другие две. Откройте outline view используя кнопку Show Document Outline в левом нижнем углу storyboard

Проверьте, что вы выбрали все три кнопки.

Теперь они подсвечены в outline view. Зажав Command и нажимая на каждую кнопку вы можете выбрать их в outline view.

После выбора, нажмите на кнопку Embed In на панели Auto Layout, которая располагается в нижнем правом углу storyboard. Появится меню с доступными параметрами вставки. Выбираем Stack View:

Xcode вставит кнопки в новый stack view за вас.

Stack View Constraints

В то время как stack view обеспечивает позиционирование кнопок, вам все еще нужно добавить Auto Layout constraints для размещения самого stack view.

Когда вы вставили view в stack view, это привело к потери constraints, которые были установлены к другим views. На пример, до встраивания кнопок в stack view, верхняя граница кнопки Submit Rating имела вертикальный отступ к нижней границе RATING label:

Выберите кнопку Submit Rating и убедитесь, что она больше не имеет никаких constraints:

Так же в Size inspector (Option-Command-5) можно увидеть, что больше нет никаких constraints: 

Иногда, сложно выбрать нужный элемент в переполненном storyboard’s view controller. Вы можете выбрать элемент из outline view или использовать Shift и right-click или Control-Shift-click на элемент, который хотите выбрать. Отобразится контекстное меню с иерархией view в области, на которую вы нажали. Выберите stack view нажав на него в этом меню.

Теперь когда вы выбрали Stack View, вы можете добавлять к нему constraints.

Нажмите на кнопку Add New Constraints в панели Auto Layout, чтобы увидеть меню установки новых constraints.

Во-первых, поставьте галочку к пункту Constrain to margins. Затем, добавьте соответствующие к границам вашего stack view:

Top: 20, Leading: 0, Trailing: 0, Bottom: 0

Перепроверьте числа введенные для top, leading, trailing, и bottom constraints. Убедитесь, что у вас активированы четыре красных I-столбиков и Constrain to margins. Затем, нажмите на кнопку Add 4 Constraints.

Сейчас у stack view правильный размер, но оно растянуло первую кнопку, чтобы заполнить любое дополнительное пространство.

Внешний вид Stack View

Свойство, которое определяет как stack view расположить свои subviews вдоль своей оси — distribution. В настоящий момент, установлено — Fill, которое означает, что subviews полностью заполнит stack view вдоль своей оси. Чтобы добиться этого, stack view будет только расширять одну из своих subviews, заполняя пустое пространство. В частности, он расширяет view с низким горизонтальным приоритетом content hugging или если все приоритеты равны — расширяет первую view.

Тем не менее, вы не хотите, чтобы кнопки заполняли stack view полностью — вы хотите чтобы они были равно удалены друг от друга.

Проверьте, что stack view все ещё выбран и перейдите в раздел Attributes inspector. Измените Distribution на Equal Spacing:

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

Когда верстаете, всегда спрашивайте себя соответствуют ли элементы доступному пространству.

Вот пример того, как ваш контент может влиять на пользовательское восприятие: Измените title кнопки Wikipedia на Wikipedia website и запустите приложение. Поверните симулятор в альбомный режим, чтобы увидеть разницу.

В портретной ориентации, где расстояние меньше, текст в последней кнопке обрезается, хотя в альбомной ориентации все хорошо.

Это то, с чем вы часто сталкиваетесь, особенно на более узких экранах, таких как iPhone SE.

К счастью, это легко фиксится. С выбранным stack view возвращаемся в раздел Attributes inspector. Меняем свойство Distribution на Fill Proportionally и меняем значение spacing на 10:

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

Измените имя кнопки на предыдущее.

Поздравляем, вы реализовали своей первый stack view!

Без Stack View

Чтобы решить проблему расстояния без stack view, вам придется использовать одну промежуточную view, между каждой парой кнопок, задавая одинаковые constraints ширины ко всем промежуточным views, а так же несколько дополнительных constraints для правильного размещения промежуточных views.

Это будет выглядеть примерно следующим образом. Для наглядности на скриншоте промежуточное view изображается как светло серый фон:

Это не настолько проблематично, если вам нужно сделать это один раз в storyboard, но многие views динамичные. Это не простая задача добавить новую кнопку, либо спрятать, либо удалить имеющуюся кнопку во время работы приложения из-за примыкающих промежуточных views и constraints.

Чтобы спрятать view в stack view, установите для нужной view свойство hidden — true, а stack view обработает все остальное. Как вы установите расстояние под WEATHER label когда юзер скроет текст под ним? Вы будете делать это в уроке, как только добавите labels для раздела weather в stack view.

Примечание: Сейчас вы знаете как задавать расстояние между subviews в вашем stack. Но что, если вы хотите разное разное расстояние после определенной subview? Начиная с iOS 11, вы можете сделать это используя setCustomSpacing:afterView.

В следующей части вы прочитаете как изменить stack view, создать вертикальный stack view и как разные свойства stack view влияют layout.

До скорых встреч!