Статьи

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

Авто макет доступен уже несколько лет, но с iPhone 6 и 6 Plus он стал необходимостью для проектов. Хотя это не всегда было особенно легко в использовании, Xcode постоянно видел улучшения в Интерфейсном Разработчике, чтобы упростить интеграцию Auto Layout. В этом руководстве вы узнаете, как использовать язык визуальных форматов с помощью Swift для создания ограничений Auto Layout в коде.

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

Язык визуального формата — это декларативный язык, который используется для определения ограничений Auto Layout для представлений. Его синтаксис выразителен и прост для понимания, когда вы просматриваете код. Предполагаемые ограничения должны быть немедленно сняты с чтения оператора языка визуального формата, и они очень похожи на предложение.

Ограничения Auto Layout с различными приоритетами, вертикальными макетами, интервалами и размерами могут быть созданы с использованием синтаксиса Visual Format Language. Он определяется внутри строковой переменной и затем передается в методы уровня класса constraintsWithVisualFormat:options:metrics:views: and
constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant: класса NSLayoutConstraint .

Язык визуального формата может быть особенно полезен, когда в Интерфейсном Разработчике нет возможности добавить ограничения Auto Layout, например, когда часть пользовательского интерфейса вашего приложения должна быть создана программно.

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

Откройте Xcode и выберите New> Project … из меню File . Выберите Single View Application из списка шаблонов приложений iOS и нажмите Next .

Затем назовите ваш проект и введите название и идентификатор вашей организации. Выберите « Универсальный» в списке « Устройства» , нажмите « Далее» и выберите место для сохранения проекта. Выберите Swift в качестве языка программирования.

Для начала создайте три переменные типа UIView . Откройте ViewController.swift и добавьте следующий код над методом viewDidLoad :

1
2
3
var vwBlue:UIView!
var vwRed:UIView!
var vwGreen:UIView!

Создайте функцию с именем initViews в нижней части контроллера представления void качестве его возвращаемого типа. Эта функция инициализирует представления и добавляет их в иерархию представлений. Обязательно вызовите эту функцию в viewDidLoad после вызова метода viewDidLoad суперкласса.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
func initViews() -> Void
{
    //Initialize
    vwRed = UIView()
    vwBlue = UIView()
    vwGreen = UIView()
     
    //Prep auto layout
    vwRed.setTranslatesAutoresizingMaskIntoConstraints(false)
    vwBlue.setTranslatesAutoresizingMaskIntoConstraints(false)
    vwGreen.setTranslatesAutoresizingMaskIntoConstraints(false)
     
    //Coloring
    vwRed.backgroundColor = UIColor.redColor()
    vwBlue.backgroundColor = UIColor.blueColor()
    vwGreen.backgroundColor = UIColor.greenColor()
     
    //Add them to the view
    self.view.addSubview(vwRed)
    self.view.addSubview(vwBlue)
    self.view.addSubview(vwGreen)
}

При использовании Auto Layout для представлений, созданных в коде, необходимо учитывать несколько предостережений. Первый связан со значением свойства translatesAutoresizingMaskIntoConstraints . Это свойство имеет значение true по умолчанию, что означает, что ограничения Auto Layout будут созданы на основе маски авторазмера представления . Мы хотим, чтобы представление соблюдало ограничения Auto Layout, которые мы добавим, поэтому для этого свойства должно быть установлено значение false .

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

Давайте начнем с простого примера языка визуального формата. Для красного представления vwRed мы добавим ограничения Auto Layout, которые сделают его такого же размера, как и его суперпредставление. Это полезно в сценарии, где вы добавляете фоновое изображение.

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

Создайте функцию с именем createConstraints с возвращаемым void типом в нижней части класса контроллера представления. Не беспокойтесь о синтаксисе. Мы еще createConstraints к createConstraints функции createConstraints .

01
02
03
04
05
06
07
08
09
10
11
12
13
func createConstraints() -> Void
{
    //Views to add constraints to
    let views = Dictionary(dictionaryLiteral: («red»,vwRed),(«blue»,vwBlue),(«green»,vwGreen))
     
    //Horizontal constraints
    let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(«H:|[red]|», options: nil, metrics: nil, views: views)
    self.view.addConstraints(horizontalConstraints)
     
    //Vertical constraints
    let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(«V:|[red]|», options: nil, metrics: nil, views: views)
    self.view.addConstraints(verticalConstraints)
}

Вызовите эту функцию в конце функции initViews мы создали ранее. Создайте и запустите проект, нажав Ctrl + R или нажав кнопку воспроизведения в левом верхнем углу. Симулятор iOS запустится, показывая красный вид, занимающий весь экран, как и предполагалось.

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

"H:|[red]|"

Сначала мы определяем, что это будет горизонтальное ограничение, начиная строку с буквы H По умолчанию используется горизонталь, но рекомендуется включить ее, чтобы сделать ее более очевидной. За направлением ограничения следует двоеточие.

| или символ трубы символизирует суперпредставление представления. Чтобы добавить пробел между двумя элементами, используется символ - или тире, и между ними можно поместить целочисленные значения, чтобы создать фиксированный или переменный интервал. На ссылки ссылаются ключи, предоставленные в словаре, переданные в constraintsWithVisualFormat . Каждый вид заключен в квадратные скобки.

Обратите внимание, как вся строка визуально соответствует изображению из симулятора. Это написано как предложение, которое будет читать что-то вроде: «По горизонтали красный вид должен расширять всю ширину своего суперпредставления без заполнения».

Теперь, когда у вас есть createConstraints представление о синтаксисе, мы собираемся отредактировать функцию createConstraints чтобы добавить ограничения Auto Layout для двух представлений.

В функции createConstraints отредактируйте переменную horizontalConstraints как показано ниже.

1
2
3
//Horizontal constraints
let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(«H:|-10-[red(>=100,<=200)]-0-[blue(==red)]-10-|», options: nil, metrics: nil, views: views)
self.view.addConstraints(horizontalConstraints)

Этот фрагмент кода действительно показывает гибкость языка визуальных форматов. Вышеприведенный оператор создает для нас ряд ограничений Auto Layout. Рядом с именем представления горизонтальные размеры определены в скобках. Для красного вида размер должен быть больше или равен 100 точкам, но меньше или равен 200 точкам.

Синий вид указывает, что он должен иметь такой же горизонтальный размер, как и красный вид, используя ==red в скобках. Это удобный способ указать, что несколько представлений должны иметь одинаковый размер. Создайте и запустите приложение в iOS Simulator. Результат должен выглядеть как на скриншоте ниже.

Когда приложение запущено в симуляторе iOS, нажмите Ctrl + стрелка влево, чтобы изменить ориентацию симулятора iOS на альбомную. Пока приложение все еще работает нормально, в консоли Xcode появилось предупреждение. Предупреждение говорит нам, что некоторые ограничения Auto Layout не могут быть выполнены. Хотя это не приведет к сбою приложения, оно может привести к неожиданным результатам в пользовательском интерфейсе приложения.

Это происходит потому, что два созданных нами вида не могут иметь ширину 200 точек и не иметь промежутков между ними, когда устройство или симулятор iOS находятся в горизонтальной плоскости. Auto Layout решает эти типы сценариев, используя приоритеты. Язык визуального формата позволяет определять приоритеты с помощью символа @ . Отредактируйте переменную horizontalConstraints чтобы она читалась следующим образом:

1
2
//Horizontal constraints
let horizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(«H:|-10-[red(>=100,<=200@20)]-0-[blue(==red)]-10-|», options: nil, metrics: nil, views: views)

Поскольку красные и синие представления теперь имеют низкий приоритет ограничения ширины, обозначенный @20 , система автоматической компоновки нарушит эти ограничения и предоставит им правильное значение во время выполнения. Запустите приложение еще раз и измените ориентацию на альбомную. Представления теперь заполняют дополнительное пространство, и XCode не производит никаких предупреждений.

Далее мы создадим ограничения для зеленого вида. Обновите реализацию функции createConstraints как показано ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
func createConstraints() -> Void
{
    //Views to add constraints to
    let views = Dictionary(dictionaryLiteral: («red»,vwRed),(«blue»,vwBlue),(«green»,vwGreen))
     
    //Horizontal constraints
    let horizontalConstraintsRedBlue = NSLayoutConstraint.constraintsWithVisualFormat(«H:|-10-[red(>=100,<=200@20)]-0-[blue(==red)]-10-|», options: nil, metrics: nil, views: views)
    self.view.addConstraints(horizontalConstraintsRedBlue)
    let horizontalConstraintsGreen = NSLayoutConstraint.constraintsWithVisualFormat(«H:|[green]|», options: nil, metrics: nil, views: views)
    self.view.addConstraints(horizontalConstraintsGreen)
     
    //Vertical constraints
    let verticalConstraintsRed = NSLayoutConstraint.constraintsWithVisualFormat(«V:|[red]-10-[green(40)]|», options: nil, metrics: nil, views: views)
    self.view.addConstraints(verticalConstraintsRed)
    let verticalConstraintsBlue = NSLayoutConstraint.constraintsWithVisualFormat(«V:|[blue]-10-[green(40)]|», options: nil, metrics: nil, views: views)
    self.view.addConstraints(verticalConstraintsBlue)
}

Поскольку ограничение horizontalConstraintsGreen не определяет конкретную ширину или интервал для своего суперпредставления, оно будет охватывать всю длину. Вертикальное ограничение гарантирует, что оно будет 40 точек высотой с 10 точками расстояния между красным и синим видами.

Если вы запустите приложение еще раз, зеленый вид охватывает всю ширину экрана, а красный и синий вид останутся над ним, как и прежде. Когда симулятор iOS поворачивается в горизонтальное положение, представления сохраняют свои позиции и соответственно изменяют размер.

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

1
let metrics = Dictionary(dictionaryLiteral: («spacing», 10),(«lowWidth»,100),(«highWidth»,200),(«priority»,20),(«redBlueSpacing»,0),(«greenHeight»,40))

Теперь вместо использования жестко закодированных значений мы можем использовать значения словаря metrics , что делает объявления ограничений более читабельными. Отредактируйте функцию createConstraints последний раз, используя новый словарь metrics .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
func createConstraints() -> Void
{
    //Views to add constraints to
    let views = Dictionary(dictionaryLiteral: («red»,vwRed),(«blue»,vwBlue),(«green»,vwGreen))
    //Metrics for Visual Format string
    let metrics = Dictionary(dictionaryLiteral: («spacing», 10),(«lowWidth»,100),(«highWidth»,200),(«priority»,20),(«redBlueSpacing»,0),(«greenHeight»,40))
     
    //Horizontal constraints
    let horizontalConstraintsRedBlue = NSLayoutConstraint.constraintsWithVisualFormat(«H:|-spacing-[red(>=lowWidth,<=highWidth@priority)]-redBlueSpacing-[blue(==red)]-spacing-|», options: nil, metrics: metrics, views: views)
    self.view.addConstraints(horizontalConstraintsRedBlue)
    let horizontalConstraintsGreen = NSLayoutConstraint.constraintsWithVisualFormat(«H:|[green]|», options: nil, metrics: nil, views: views)
    self.view.addConstraints(horizontalConstraintsGreen)
     
    //Vertical constraints
    let verticalConstraintsRed = NSLayoutConstraint.constraintsWithVisualFormat(«V:|[red]-spacing-[green(greenHeight)]|», options: nil, metrics: metrics, views: views)
    self.view.addConstraints(verticalConstraintsRed)
    let verticalConstraintsBlue = NSLayoutConstraint.constraintsWithVisualFormat(«V:|[blue]-spacing-[green(greenHeight)]|», options: nil, metrics: metrics, views: views)
    self.view.addConstraints(verticalConstraintsBlue)
}

Вы можете быть удивлены, почему высота зеленого вида была определена дважды. Это потому, что язык визуального формата работает в строках и столбцах. При использовании языка визуальных форматов подумайте о добавлении ограничений слева направо на одну «строку» представления для горизонтальных ограничений. Для вертикальных ограничений вы должны думать о столбцах.

Большинство ограничений Auto Layout, которые вы будете использовать, могут быть выражены с помощью языка визуального формата. Однако есть некоторые, которые не могут. Например, ограничение фиксированного соотношения сторон не может быть создано с использованием языка визуального формата. Это не может быть выполнено с помощью синтаксиса Visual Format Language, потому что следующая строка не может быть проанализирована:

H:|imageView.width = 2 * imageView.height|

Вы все еще можете использовать Auto Layout в своем коде для достижения этих типов ограничений, используя традиционный метод constraintWithItem .

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

До того, как Auto Layout был доступен для разработчиков, отслеживание того, как изменить размеры представлений для различных категорий устройств, было большой работой. Благодаря Auto Layout и Visual Format Language это стало более интуитивно понятным, что упрощает поддержку пользовательских интерфейсов на всех устройствах.