В данной статье вы узнаете, насколько просто в WatchKit выравнять UI-элементы.

Новый механизм

WatchKit предоставляет новый механизм выравнивания элементов на экране, который в большей степени полагается на размер контента и расстояния между элементами интерфейса. Ни каких констрейнтов.
Для того чтобы создавать сложные интерфейсы, необходимо четко различать три новые концепции: groups, content sizing и relative spacing.

Groups

Группы — экземпляры класса WKInterfaceGroup, который является наследником WKInterfaceObject.

Если при разработке под iOS вы когда-нибудь использовали пустые вьюхи, как контейнер, то группы в WatchKit покажутся вам знакомыми. Точно так же, как с UIView, для WKInterfaceGroup вы можете настроить совершенно разное поведение и внешний вид.

Заглянув в интерфейс класса, можно увидеть методы, которые позволяют настроить кастомный вид:

setBackgroundColor(_:) — смена цвета фона;

setCornerRadius(_:) — смена радиуса;

setBackgroundImage(_:) — устанавливает фоновое изображение;

setBackgroundImageData(_:) — устанавливает фоновое изображение из бинарного представления, обычно используется при анимированной смене изображений;

setBackgroundImageNamed(_:) — устанавливает фоновое изображение из каталога ассетов;

startAnimating() — начинается анимация по смене фоновых изображений;

startAnimatingWithImagesInRange(_:duration:repeatCount:) — подобен startAnimating(), но с большим контролем;

stopAnimating() — останавливает любую анимацию.

Теперь давайте перейдём в Attributes Inspector в Interface Builder, чтобы посмотреть, какие здесь есть инструменты для построения красивого UI.

group_attributesinspector

Layout является наиболее важным атрибутом, который определяет вдоль какой оси внутри группы будут выравниваться элементы. Можно использовать или горизонтальное или вертикальное выравнивание.
layout

NOTE: Обратите внимание, что при горизонтальном выравнивании, слишком длинные динамические элементы(например, label) могут выталкивать за пределы видимости другие элементы.

Insets позволяют создавать зазоры между группой и её содержимым. Очень похоже на UIEdgeInset. Вы можете независимо менять верхний, нижний, левый и правый отступы.
insets

Согласно Apple Watch Human Interface Guidelines рекомендуется «приклеивать» элементы к краям экрана, так как черный ободок физического экрана обеспечивает естественные отступы.

Spacing регулирует расстояние между элементами группы.
spacing

Атрибуты в следующем разделе достаточно очевидны: вы можете менять фоновое изображение, режим отрисовки, решать, следует ли применять анимацию к фоновому изображению или просто выбирать цвет фона. Последним атрибутом является радиус, который меняет радиус углов группы. По умолчанию значение радиуса — 6 поинтов, но вы заметите это только при установке или фонового изображения или фонового цвета.

При изменении радиуса не забывайте обращать внимание на расположение и размер вашего контента: группа автоматически обрезает всё, что выходит за пределы границ с закругленными углами.

Сontent sizing

Еще одна интересная особенность механизма выравнивания в WatchKit заключается в том, что размер группы обусловлен размером всего контента, входящего в эту группу.

В WatchKit пространство, занимаемое текстом, определяется с помощью NSAttributedString, который содержит такие атрибуты, как шрифт, интервал между строками и цвет. WatchKit рендерит текст за «кадром», определяет высоту и ширину, основанные на bounding box строки, а затем на основе этих расчетов использует выравнивание.

Вместо того, чтобы суетиться с размерами текста, группа просто устанавливает свойство Size To Fit Content, и WatchKit берет на себя всё остальное. Для того, чтобы достичь этого же эффекта в iOS, пришлось бы устанавливать ряд констрейнтов между вашей вьюхой и внешним scorll view.

Точно также, как и в iOS, количество строк в элементе интерфейса, содержащего текст, играет огромную роль: атрибут Lines информирует элемент усечь любой текст, число строк которого превышает значение, установленное в атрибуте. Установка значения в 0 позволяет не ограничивать количество строк.

Relative spacing

Последней важной особенностью механизма является возможность изменять размер и положение элемента интерфейса в зависимости от размера и положения его родителя. В WatchKit родителем всегда будет группа.

WKInterfaceController, являющийся корневым элементов интерфейса, также представляет собой группу. Ниже приведены атрибуты, доступные при редактировании любого экземпляра WKInterfaceObject в Interface Builder.
snimok-ekrana-2017-01-07-v-14-49-00

Вы можете изменить оба атрибута горизонтального и вертикального положения. Для горизонтального выравнивания доступны свойства: Left/Center/Right. Для вертикального — Top/Center/Bottom.

Механизм выравнивания обновляет положение любого элемента интерфейса в трёх случаях:

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

Вы можете изменить ширину и высоту элемента, чтобы соответствовать размеру контента(Size To Fit Content), размеру контейнера(Relative to Container) или установить фиксированное значение(Fixed).

Установка свойства в Relative to Container, позволяет указать множитель от 0 до 1, который обозначает в виде доли размер элемента относительно размера его родительского элемента. Вы также можете изменить значение Adjustment, который сбалансирует окончательный размер. Итоговая формула вычисления размеров имеет вид:

От теории к практике

По ссылке вы можете скачать готовый проект с небольшим демо. А сейчас разберём основные моменты в проекте.

Откроем файл Interface.Storyboard и посмотрим, какую иерархическую структуру образуют UI-элементы. Мы видим, что у контроллера есть два родительских элемента: группа и кнопка, которая также в данном случае является группой/контейнером(ниже объясню подробнее). Группа в свою очередь содержит еще одну группу и картинку. Данный пример представляет собой один простой пост из соцсети для привычного отображения картинка с подписью должны располагаться в группе вертикально. Открыв Attributes Inspector, и, взглянув на атрибут Layout, мы увидим, что для данного расположения выбрано значение Vertical.

demo_1

У группы, содержащей лэйбл с никнеймом «cocoa-beans» и лэйбл со временем публикации, значение Layout равно Horizontal. Для того, чтобы время было прикреплено к правому краю экрана, в разделе Alignment у атрибута Horizontal выставлено значение Right.

Ну а теперь обратим внимание на кнопку. Как я сказал ранее, данная кнопка также является группой. Если мы посмотрим в Attributes Inspector, то заметим, что у атрибута Content выбрано значение Group. WatchKit позволяет таким образом осуществлять интерактивное взаимодействие с целой группой элементов.

demo_2

В эту группу мы поместили три лэйбла(collapsedCommentLbl, expandedCommentLbl, moreLbl). Лэйблы collapsedCommentLbl и expandedCommentLbl имеют одинаковый текст, но expandedCommentLbl скрыт. Для чего? Через 10 секунд об этом узнаете.

Теперь пришло время посмотреть всё-таки на код:

import WatchKit
import Foundation

class InterfaceController: WKInterfaceController {

    // 1
    @IBOutlet var collapsedCommentLbl: WKInterfaceLabel!
    @IBOutlet var expandedCommentLbl: WKInterfaceLabel!
    @IBOutlet var moreLbl: WKInterfaceLabel!
    
    var expanded = false
    
    // 2
    @IBAction func onMoreButton() {
        
        expanded = !expanded
        
        collapsedCommentLbl.setHidden(expanded)
        expandedCommentLbl.setHidden(!expanded)
        
        moreLbl.setText(expanded ? "Скрыть" : "Показать")
    }
}

1 — объявляем три IBOutlet’а для каждого из лэйблов и булевскую переменную expanded, отвечающую за формат текста;

2 — объявляем IBAction для кнопки. Внутри этого метода мы меняем значение expanded на противоположное, и скрываем/показываем свернутый и развернутый текст- все предельно просто.

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

aw_layoutdemo_gif

На этом всё. Спасибо за внимание.

Следите за обновлениями и подписывайтесь на группу в ВК: cocoa-beans.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.