Автопозиционирование Часть 1: iOS 8

Туториалы

Автопозиционирование Часть 1: iOS 8

Бывало ли у вас такое, что вы пытались сделать ваше приложение удобным и красивым как в вертикальной так и в горизонтальной ориентации устройства? Создание макета, который поддерживается iPhone, iPad доводит вас до грани безумия? Скажите отчаянию - нет, так как у меня для вас хорошие новости!

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

До этого момента, если ваши проекты были достаточно сложными, то вам приходилось писать много кода для поддержки этих адаптивных макетов. Вы будете очень рады узнать, что это больше не проблема, так как iOS 6 принес нам прекрасную опцию для iPhone и iPad - автопозиционирование. Начиная с Xcode 5, в iOS 7 и iOS 8, использовать автопозиционирование стало значительно проще. Если вы пытались сделать это в Xcode 4 и в конце концов сдались, то не отчаивайтесь - дайте шанс Xcode 6 и вы увидите на сколько все стало проще! 

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

Так что запаситесь терпением и приготовьтесь стать мастерами автопозиционирования!

Проблема с исходниками и распорками

Без сомнения вы знакомы с autosizing masks(маски с автоматической сменой размера), так же известными как модель "исходники и распорки". Маска определяет что случится с видом, если его родитель (или супервид) изменит свой размер. Имеет ли он подвижные или фиксированные отступы (распорки), и что случится с шириной и высотой (исходниками)?

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

Автопозиционирование хорошо работает с простыми интерфейсами, но оно быстро ломается, когда интерфейсы становятся более замысловатыми. Давайте посмотрим на пример, где исходные размеры и отступы не обрезают интерфейс.

Откройте Xcode 6 и создайте новый проект Single View Application. Давайте назовем его "StrutsProblem".

Нажмите на Main.storyboard, что открыть его в «interface builder». Также, не забудьте отменить автопозициониарование в сториборд. Вы можете сделать это в File inspector, в первой из шести вкладок:

Уберите галочку с чекбокса Use Autolayout. Сейчас storyboard использует модель struts-and-springs, что означает использование значений исходных размеров и отступов.

Перетащите три вида на ваш основной вид, чтобы они выглядели вот так:

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

Каждый вид имеет по 20 единиц от границ окна, между видами так же 20 единиц. Нижний вид шириной 280 единиц, верхние по 130. Все виды имеют высоту по 254 единиц.

Запустите приложение на симуляторе iPhone 5s и поверните его в горизонтальное положение. Это заставит ваше приложение выглядеть вот так:

Заметка

Вы можете повернуть симулятор, если пройдете в меню Hardware\Rotate Left и Rotate Right, или можно зажать клавишу ⌘ и один раз нажать стрелку влево или вправо, для соответствующего вращения.

А вообще вместо нашего результата, вы бы, наверное, хотели видеть что-то вроде вот этого:

Очевидно, что маски для всех трех видов, в итоге, оставляют желать лучшего. Поменяйте установки автоматического изменения размера, левого верхнего вида, на:

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

Аналогично, меняем значения для правого верхнего вида:

И меняем нижний вид:

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

Близко, но не совсем то. Расстояние между видами некорректно. Если взглянуть с другой стороны, то размеры видов не на 100% правильные. Маски говорят видом о необходимости измениться, так как изменился их родитель, но на сколько необходимо поменяться, им точно не известно.

Вы можете поиграться с авторазмерами (смысл от autosizing), к примеру, поменять настройки изменяемой ширины и высоты (исходники). Но вы не получите точно то, что должны, так как расстояние между видами не будет 20 единиц.

Для решения этой проблемы - метода с исходниками и отступами, нам необходимо написать некоторый код.

UIKit посылает несколько сообщений в ваш view controller: до, во время и после вращения вашего пользовательского интерфейса. Вы можете перехватить эти сообщения для внесения своих изменений в позиционирование вашего UI(user interface - пользовательский интерфейс). Обычно, вы можете переписать viewWillLayoutSubviews для изменения рамок любого из видов, которые вам нужно переназначить.

До того, как вы сможете сделать что-либо, вам необходимо создать outlet свойства для возможности сослаться на виды, которые нужно установить.

Переключитесь в Assistant Editor (кнопка с двумя пересекающимися кружочками на верхней панели Xcode). Перетащите каждый вид с зажатым CTRL в ViewController.swift:

Свяжите эти свойства соответственно:

@property (weak, nonatomic) IBOutlet UIView *topLeftView;
@property (weak, nonatomic) IBOutlet UIView *topRightView;
@property (weak, nonatomic) IBOutlet UIView *bottomView;

Добавьте следующий код в ViewController.swift:

- (void)viewWillLayoutSubviews
{
    if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
    {
        CGRect rect = self.topLeftView.frame;
        rect.size.width = 254;
        rect.size.height = 130;
        self.topLeftView.frame = rect;
 
        rect = self.topRightView.frame;
        rect.origin.x = 294;
        rect.size.width = 254;
        rect.size.height = 130;
        self.topRightView.frame = rect;
 
        rect = self.bottomView.frame;
        rect.origin.y = 170;
        rect.size.width = 528;
        rect.size.height = 130;
        self.bottomView.frame = rect;
    }
    else
    {
        CGRect rect = self.topLeftView.frame;
        rect.size.width = 130;
        rect.size.height = 254;
        self.topLeftView.frame = rect;
 
        rect = self.topRightView.frame;
        rect.origin.x = 170;
        rect.size.width = 130;
        rect.size.height = 254;
        self.topRightView.frame = rect;
 
        rect = self.bottomView.frame;
        rect.origin.y = 295;
        rect.size.width = 280;
        rect.size.height = 254;
        self.bottomView.frame = rect;
    }
}

Обратный вызов происходит тогда, когда view controller поворачивается в новое положение. Выглядит так, что ориентация view controller повернулась и изменила размеры видов соответственно с запрограммированными размерами, основанными на разрешении экрана iPhone. Обратный вызов происходит внутри анимационного блока, так что изменения так же анимируются.

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

Запустите приложение в горизонтальном виде - выглядит чудесно, правда? 

Это работает, но вам пришлось писать достаточно много кода, для такого простого отображения интерфейса. А представьте что вам придется сделать для отображения сложного интерфейса, особенно, где используются динамические составляющие (изменение размеров вида, не фиксированное количество подвидов и т.д.)

Теперь, запустите свое приложение на 4s дюймовом симуляторе. Упс, позиции и расположение видов неверно, из-за того, что они были рассчитаны на другое разрешение в методе viewWillLayoutSubviews, который основан на расчете экрана (320х568 вместо 320х480). Но вы можете добавить еще несколько if выражений для того, чтобы проверить размер экрана и применить соответствующий код. И как вы видите, этот подход не очень-то хорошо работает.

Заметка

Есть и другой подход - вы можете разделить nib файл вертикальный от nib-файла горизонтального. Когда устройство поворачивается, вы загружаете вид из другого nib-файла, то есть, просто замещаете вид. Но чтобы это сделать, вам придется немало потрудиться. Такой метод не очень практичный, когда вы используете сториборды вместо nib-файлов.

Автопозиционирование - наше спасение!

Через пару минут вы увидите, как можно получить тот же эффект с помощью автопозиционирования. Сначала удалите viewWillLayoutSubvi  ews из ViewController.swift, потому что мы сделаем все это без написания какого-либо кода.

Выделите Main.storyboard в панели инспектора файлов, чекните Use Autolayout для разрешения использования автопозициониарования, для вашего файла сториборд:

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

Давайте воспользуемся автопозиционированием. Зажмите ⌘, пока вы кликаете на два верхних вида(зеленый и желтый), так, чтобы оба получились выделенными. Идите в Xcode Editor далее Pin\Width Equally:

Выделите те же два вила и идите в меню Editor\Pin\Horizontal Spacing. Если вам кажется, что эти два вида выделены после предыдущего действия, то запомните, что вам их нужно перевыбрать, так как они находятся в специальном режиме отображения.

Оранжевый «двутавр», отображенный между двумя видами, является ограничением между этими двумя видами. В итоге, вы добавили два ограничения: ограничение - равная ширина обоих видов(отображенные оранжевые двутавры с синими кружками со знаком равенства) и ограничение - горизонтального расстояния между видами. Ограничения (constraints) являются основным инструментом, отображающим взаимодействие между элементами интерфейса. Это может выглядеть немного устрашающе, но на самом деле это не так сложно, и выучив их один раз, вы можете ими постоянно пользоваться, без каких-либо проблем.

Для левого верхнего вида выберите Editor\Pin в меню:

  • Top Space to Superview
  • Leading Space to Superview

Для вида справа:

  • Top Space to Superview
  • Trailing Space to Superview

Для нижнего большого вида:

  • Leading Space to Superview
  • Trailing Space to Superview
  • Bottom Space to Superview

В итоге, у вас должны были установиться следующие ограничения:

Обратите внимание, что все "двутавры" оранжевые. Это значит, что ваше позиционирование элементов неполное и, что у автопозиционирования недостаточно данных для просчета размеров, и расположений элементов. Решение таково, что мы добавляем ограничения до тех пор, пока они не станут голубыми.

Удерживайте ⌘ и выберите все три вида. Теперь, пройдите в Editor\Pin\Heights Equally.

Далее, выделите верхний левый вид и нижний, через клавишу ⌘, как и раньше, и пройдите в Editor\Pin\Vertical Spacing.

Теперь, ваш интрефейс билдер должен выглядеть вот так:

Все ваши Т-бары стали голубыми. Автопозиционированию достаточно информации для того, чтобы рассчитать валидное расположение элементов. Это выглядит немного запутанно, но это потому, что ограничения Equal Heights, Equal Widths занимают много места.

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

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

Вам нужно установить взаимоотношения, которые известны нам теперь, как ограничения:

  • Верхний левый и верхний правый виды всегда одной ширины.
  • Есть 20 единичный отступ одного верхнего вида от другого.
  • Все виды имеют всегда одну и ту же высоту.
  • Есть отступ нижнего вида от верхнего на 20 единиц.
  • Есть 20 единичный отступ всех видов от краев экрана(верхний, нижний, левый, правый по отношению к виду родителя)

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

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

Так вот, если вы нажмете на на какое-либо ограничение в схеме документа, то вы увидите, как выделяется это ограничение в интерфейс билдере.

Ограничения являются реальными объектами, они так же имеют свои атрибуты. К примеру, выберите ограничение, которое создает отступ между двумя видами сверху, затем переключитесь в Attribute Inspector. Здесь вы можете изменить отступ, изменив значение в поле Constant.

Выставьте значение этого поля на 100 и запустите приложение снова. Теперь, расстояние между верхними видами стало намного шире:

Автопозиционирование намного более гибкий инструмент, чем исходные размеры и отступы. Далее вы узнаете, как применять ограничения в «Interface builder» для создания различных шаблонов.

Как работает автопозиционирование

Как вы могли уже заметить, основным инструментом автопозиционирования являются ограничения (constraints). Ограничения определяют геометрические отношения между видами. К примеру, вы можете иметь ограничение, которое говорит:

"Правый край ярлыка A соединен с левым краем кнопки пустотой, ширина которой равна 20 единицам."

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

До автопозиционирования вы всегда должны указывать размеры ваших видов: путем их размещения на специфические места в «Interface builder», или передав прямоугольник вида в initWithFrame, или можно указать свойства frame, bounds, center вида.

Для приложения, которое вы только что сделали, вы определили размеры:

Вы так же устанавливаете меняющие размер маски для этих видов:

Больше вы не должны думать о дизайне как мы описывали чуть выше. Автопозиционирование - это все, что вы должны знать о дизайне:

Размеры и позиционирование видов теперь уже не имеют такого важного значения, только ограничения имеют существенный вес. Конечно, когда вы перетаскиваете какой-то элемент типа кнопки или ярлыка на свой чистый холст(экран), вы указываете точный размер и позицию, но это только лишь дизайн, который помогает «interface builder» правильно расставить ограничения.

Сделать дизайн таким, каким вы его видите

Большое преимущество в использовании ограничений заключается в том, что вы больше не веселитесь с координатами, чтобы заставить ваши виды появляться там, где это необходимо. Вместо этого, вы описываете для автопозиционирования то, как виды расположены относительно друг друга, и он выполняет всю тяжелую работу за вас. Такой метод называется проектирование по цели (или designing by intent).

Когда вы проектируете по цели, вы объясняете какая ваша цель, но не говорите как вы хотите прийти к этой цели. Вместо того, чтобы говорить: "левый верхний угол кнопки расположен по координатам (20, 230)", теперь вы говорите:

"Кнопка располагается по центру родителя, и она расположена на фиксированном расстоянии от левого края родителя."

Если мы объясняем таким образом, то мы даем возможность автопозиционированию вычислить все необходимые для него данные того, где должна появиться кнопка. Нам не нужно переживать касательно размера, так как кнопка тоже будет изменяться.

Другие примеры проектирования по цели(автопозиционирование может обрабатывать все эти инструкции):

  • "Эти два текстовых поля должны быть одного размера."
  • "Эти две кнопки должны всегда двигаться вместе."
  • "Эти два ярлыка всегда должны быть расположены справа."

Это все делает пользовательский интерфейс намного более наглядным. Вы просто объявляете ограничения, и система автоматически все размещает для вас.

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

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

Теперь включить поддержку различных языков для вашего приложения стало значительно проще, осталось лишь перевести текст и все!

И угадайте какой способ самый лучший для изучения ограничений? Конечно же поиграть с ними! 

Заметка

Автопозиционирование может быть полезным не только при смене позиции устройства, но и при масштабировании вашего интерфейса, в зависимости от размера экрана. Это было сделано не случайно, так как тогда вышел iPhone 5, который имел другие размеры экрана, а потом и iPhone 6. И при работе с динамикой, начиная с iOS 7, автопозиционирование стало даже еще более важным элементом. Пользователи могут менять глобальные настройки текста, а благодаря автопозиционированию, это легко осуществить в ваших приложениях.

Играем с ограничениями

Закройте ваш проект и создайте новый проект iPhone, выберите Single View Application. Назовите этот проект "Constraints". Новый проект, который вы создали в Xcode 5 или выше, автоматически считает, что вы хотите использовать автопозиционирование, так что вам ничего делать не нужно, чтобы активировать его.

Кликните на Main.storyboard для того, чтобы открыть «interface builder». Перетащите Button на ваш холст. Обратите внимание, что когда вы перетаскиваете кнопку, время от времени появляются голубые линии. Они известны как guides (или ориентиры):

Ориентиры находятся по краям экрана и в центре:

Если вы раньше работали в «interface builder», то вы без сомнения видели эти ориентиры. Они очень облегчают позиционирование и выравнивание элементов.

В Xcode 4 при включенном автопозиционировании ориентиры используются для других целей. Вы все еще можете использовать их для выравнивания, но они так же говорят вам, где будут располагаться новые ограничения. Если вы перенесете кнопку в верхний левый угол к синим ориентирам, то ваш сториборд будет выглядеть так:

Здесь вы видите, что две голубые линии соприкасаются с кнопкой. Объекты похожие на двутавры или отрезки вида буквы "Т" называются ограничениями. Не важно где вы размещаете свой элемент, так как ограничения, которые появляются на экране^ всегда валидны. В теории все это выглядит как классная идея, но на практике это делает использование автопозиционирования невероятно сложным из вашего интерфейс билдера.

К счастью, это поменяли в Xcode, начиная с 5 версии, теперь вы можете переместить кнопку на экран, и никаких ограничений не появится:

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

Но что же теперь делать? Как вы знаете, автопозиционированию для правильного функционирования, нужно задать достаточное количество ограничений. Так же, это необходимо для правильного определения размеров и позиций видов, но у вас нет никаких ограничений. Можно ли считать это неполным позиционированием?

По сравнению с Xcode 4 и Xcode 5, в 6 версии вас больше не заставляют всегда иметь валидное расположение.

Заметка

Это плохая идея запускать приложение с незаконченным расположением элементов, потому что автопозиционирование не может корректно рассчитать куда должны двигаться виды. Так же расположения видов будут непредсказуемыми (недостаточно ограничений), или ваше приложение выдаст ошибку (слишком много ограничений). Ой-ой!

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

Начиная с Xcode 5 это неудобство пропало. Теперь Xcode позволяет вам создавать неполное позиционирование, но также, он указывает на то, что ему нужно еще для корректной работы, или что нужно еще изменить, для правильного отображения. Использование автопозиционирования стало намного интереснее и менее трудоемким процессом, как это было ранее.

Если вы вообще не указываете ограничений, то Xcode автоматически присваивает ограничения по умолчанию, известные как automatic constraints (автоматические ограничения). Эти ограничения создаются при компиляции вашего приложения, во время постройки, а не во время создания дизайна. Автопозиционирование в Xcode 5 старается сохранить ваше первоначальное расположение, и признаться честно, нам это очень нравится.

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

Здорово, давайте поиграем с ограничениями и посмотрим, что они могут. На данный момент кнопка в верхнем левом углу не имеет никаких ограничений. Убедитесь в том, что она располагается по двум ориентирам.

Добавьте два новых ограничения к кнопке, используя Editor\Pin так, чтобы кнопка выглядела так:

Если вы еще не догадались, то это опции Leading Space to Superview и Top Space to Superview.

Все ограничения так же вы можете посмотреть в схеме документа:

На данный момент у нас всего два ограничения: первое - ограничение расстояния от левого края родителя до левого края кнопки, второе - ограничение расстояния от верхнего края родителя до верхнего края кнопки. Все это можно выразить одной фразой:

"Кнопка должна всегда располагаться на расстоянии 20 единиц от левого верхнего угла родителя."

Заметка

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

Теперь возьмите и переместите кнопку в правый верхний угол:

Ух, что такое произошло тут? В версии Xcode 4 такое передвижение кнопки сломало бы старые ограничения и назначило новые, но в Xcode 5 кнопка остается преданной старым ограничениям. Проблема в том, что размер и позиция кнопки не соответствуют размеру и позиции, которые ожидает увидеть автопозиционирование. Это называется ошибочное расположение вида.

Запустите приложение. Кнопка появится в верхнем левом углу экрана:

Когда автопозиционирование отображается оранжевым цветом, то это плохо. Интерфейс билдер отображает боксы оранжевого цвета, один с пунктирной рамочкой, другой с цельной. Бокс с пунктирной рамочкой отображает расчетное положение, вычисленное автопозиционированием, сплошная рамочка свидетельствует о расположении элемента, которое назначили вы сами. По идее эти два бокса всегда должны совпадать.

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

  • Хотите ли вы чтобы ваша кнопка была отставлена на 254 единицы от левого края? В этом случае вам нужно увеличить существующее ограничение на 234 единицы. Вот что и означает оранжевый бокс с "+234".
  • Может быть вы хотите, чтобы ваша кнопка была отставлена от правого края родителя на 20 пунктов? Для этого вам нужно убрать существующее ограничение левого края для того, чтобы было создано новое.

Обратите внимание, что вертикальное ограничение стало оранжевым. Ничего неправильного нет в этом конкретном ограничении, цвет просто означает, что этого ограничения недостаточно для точного определения позиции кнопки. Вам все еще нужно добавить ограничение по оси X.

Заметка

Вам может быть станет интересно, почему все таки Xcode не добавляет автоматически недостающее ограничение для оси X. В Xcode есть правило - добавлять автоматически ограничения только в тех случаях, если вы не выставили своих. Как только вы добавили хотя бы одно ограничение, вы сказали Xcode, что вы берете на себя ответственность за этот вид. С этого момента Xcode не создает автоматических ограничений для этого вида.

Выделите кнопку и выберите в меню Editor\Pin\Trailing Space to Superview. Это объясняет отношение как:

"Кнопка всегда должна находиться на расстоянии 20 единиц от сторон правого верхнего угла."

Запустите приложение и переверните экран в горизонтальное положение. Обратите внимание, что кнопка держит то же расстояние от правого края:

Если вы размещаете кнопку (или другой вид) по линиям ориентира и создаете ограничение, то вы получаете ограничение стандартного размера, которое определено в "HIG", в документации посвященной интерфейсу пользователей Apple iOS. Для отступов от краев стандартный размер составляет 20 единиц.

А теперь, давайте перетащим кнопку немного влево:

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

В меню, в пункте Editor, есть подпункт Resolve Auto Layout Issues. Там выберите Update Constraints. В моем случае этого говорит «interface builder», что нужно увеличить ограничение или отступ справа на 64 пункта, так что:

Здорово, наши отступы или ограничения снова стали голубыми и это значит, что наше позиционирование валидно. В схеме документа вы можете увидеть, что ограничение Horizontal Space теперь имеет в скобках значение 84, вместо 20:

Мы поработали с вертикальными и горизонтальными ограничениями и самое время познакомиться с "центральным" ограничением. Давайте перетащим новую кнопку Button на середину нижней части вашего холста так, чтобы у вас появились вот такие голубые ориентиры:

Для того, чтобы кнопка была всегда по центру родителя, вам нужно добавить горизонтальное ограничение. Пройдите в Editor\Align\Horizontal Center in Container, это добавит оранжевую длинную линию:

Эта линия оранжевая, так как вы обозначили только то, что должно происходить с осью X, но про Y вы ничего не указали. Идем в Editor\Pin для того, чтобы добавить ограничение между нижней частью кнопки и нижней частью экрана. В итоге это будет выглядеть вот так:

Если вдруг вы не знаете как это сделать, то идем в Editor\Pin\Bottom Space to Superview. Вертикальное ограничение выдерживает расстояние от кнопки до нижней части экрана (значение расстояние приравнивается стандартному отступу).

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

Вот как звучит то, что вы сделали: "Эта кнопка должна быть всегда в центре основания". Обратите внимание, что вы нигде не говорите ни об «interface builder», ни о координатах кнопки в нем, только лишь про то, где вы хотите видеть эту кнопку.

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

Вы можете увидеть изменения в Size Inspector для кнопки, которые достаточно сильно видны:

При отключенном автопозиционировании, мы можем изменить размер и позицию элемента, вписав соответствующие значения в X,Y, Width и Height. При включенном автопозиционировании вы все еще можете вписывать новые значения в эти поля, но если вы уже установили ограничения, то может так получиться, что ваш вид может быть расположен неправильно. Вам так же придется обновить ограничения, чтобы они соответствовали новым размерам вашего вида.

К примеру, изменим ширину кнопки на значение 100. Наш холст отобразит что-то вроде этого:

В свое время Xcode 4 бы заменил центрирующее ограничение по оси X на горизонтальный отступ и ограничение, которое бы заставляло кнопку иметь значение ширины равное 100, при любых ориентациях. Но Xcode 5 и более новые версии нам говорят: "Ничего страшного, что вы хотите иметь ширину кнопки равную 100, просто имейте в виду, что ваши ограничения не говорят об этом."

В случае, если вам действительно нужно иметь фиксированную ширину, например 100, то есть специальное ограничение, называющееся ограничением фиксированной ширины. Сначала нажмите Undo, чтобы вернуть кнопку в центральную позицию, и чтобы ограничения снова стали синими. Выберите кнопку и пройдите в меню Editor\Pin\Width. Этот шаг добавит вам новое ограничение, которое вы увидите под кнопкой:

Выделите ограничение, отвечающее за ширину кнопки, и в Attribute Inspector измените значение Constant на 100. Это заставит кнопку поменять ее ширину на значение 100, не зависимо от того, какая надпись на кнопке. Чтобы лучше видеть границы кнопки, давайте зададим ей цвет:

Вы можете увидеть новое ограничение в иерархии документа:

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

Вы можете подумать: "Так почему же кнопка не имела ограничения ширины ранее? Как автопозиционирование понимает, какая ширина кнопки должна быть, если нет никакого на это ограничения?"

На самом деле кнопка, сама по себе знает, какой ширины она должна быть. Она высчитывает это как ширина текста, плюс некоторый отступ до границы кнопки. Если вы размещаете какую-то картинку на заднем плане, то в расчет размера кнопки пойдет и она.

Такой способ подсчета известен как внутренний размер контента. Не все элементы имеют такой способ подсчета (например, UILabel). Если вид может рассчитать свой желательный размер, то вам не приходится возиться и выставлять ограничения. Об этом мы поговорим совсем скоро.

Для того, чтобы вернуть кнопке оптимальный размер, вам в первую очередь нужно удалить ограничение по ширине, потом пройти в меню Editor и поставить Size to Fit Content. Это восстановит размер кнопки соответственно своему содержимому.

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

Установите новую кнопку рядом с уже существующей:

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

Xcode 4 бы создал новое ограничение для одного из этих направляющих. Но в Xcode 5 и выше, если вы хотите задать какое-либо расстояние между кнопками, то вам нужно будет его создать самостоятельно. Вы видели в меню Editor\Pin наличие такого пункта, который выставляет ограничение между двумя видами, но есть даже более простой способ сделать это.

Быберите одну из кнопок и зажав CTRL, перетащите ее на другую кнопку, это будет выглядеть вот так:

Когда вы отпустите кнопку мышки, появится меню, в котором вам нужно будет выбрать Horizontal spacing:

Это создаст новое ограничение, которое будет выглядеть вот так:

Ограничение оранжевое, это означает, что нужно хотя бы еще одно ограничение. Размер кнопки известен (по размеру контента), есть ограничение по оси X. Остается добавить ограничение только по оси Y.

Так же вычислить недостающее ограничение нам позволяет Xcode. На рисунке ниже, в верхнем правом углу, есть маленькая белая стрелочка на красном фоне, если мы ее нажмем, то мы увидим выявленные проблемы позиционирования:

Ну вот и славненько! Давайте добавим недостающее ограничение. Так же зажимаем CTRL и перетаскиваем левой кнопкой мышки от новой кнопки вниз:

Всплывающее меню на этот раз имеет другие опции. Элементы всплывающего меню зависят от контекста. В нашем случае выбираем Bottom Space to Bottom Layout.

На этот раз кнопка имеет Vertical Space to the bottom и Horizontal Space (что видно в иерархии документа). Так как расстояние между кнопками очень маленькое, то может быть сложновато увидеть это ограничение.

Кликните на Horizontal Space (8) в схеме документа:

Когда вы выбираете какое-либо ограничение, то оно начинает подсвечиваться на холсте. Конкретное ограничение, которое мы выделили, говорит вот что:

"Вторая кнопка появляется всегда с левой стороны от первой кнопки, на расстоянии 8 пунктов, вне зависимости от того, где будет располагаться первая кнопка и какого размера она будет."

Выделите кнопку справа, задайте ей желтый фон и напишите вместо Button, что-то вроде A longer label. Когда вы закончите, кнопка увеличится в размере, в соответствии с текстом внутри нее, а вторая кнопка сместится. После всех этих манипуляций, левая кнопка продолжит находиться на том же самом расстоянии от правой кнопки, как мы и задумывали:

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

Задайте свежей кнопке зеленый фон.

Так как вы расположили кнопку вдоль ориентира, то расстояние между ними стандартное и равняется 8 единицам, что является рекомендацией HIG. Превратим это расстояние в ограничение путем перетаскивания с зажатым CTRL. Выберите Vertical Spacing в появившемся меню.

Заметка

Аббревиатура HIG является сокращением от iOS Human Interface Guidelines (руководства по созданию пользовательского интерфейса для платформ iOS), содержит рекомендации по созданию хорошего пользовательского интерфейса. Это является обязательным для прочтения разработчиками iOS. HIG объясняет какие элементы и почему подходят в конкретных ситуациях и приводит примеры лучших практик их использования. Вы можете ознакомиться с ними тут(англ).

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

Выберите ограничение в иерархии документа Vertical Space, который отвечает за расстояние между кнопками. Вы можете выбрать его, просто щелкнув на холсте на это ограничение в виде маленькой голубой линии, между зеленой и желтой кнопками. После чего, идите в Attribute Inspector:

Наберите значение 40 в поле Constant и обратите внимание, как меняется расстояние между кнопками. Теперь, кнопки довольно далеки друг от друга, но все равно они связаны между собой:

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

Определенно кнопки держат вертикальную дистанцию, но не горизонтальную! Причина очевидна: зеленой кнопке мы не выставили никаких ограничений по оси X. Добавление ограничения от левого края экрана до левого края кнопки не решит проблемы, так как это ограничение останется и для вертикального вида, что явно не будет смотреться хорошо. Так что вместо этого, мы объясним интерфейс билдеру следующее:

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

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

Если вы так же перетащите вашу зеленую кнопку выше по вертикали, то вы увидите, что появится оранжевая пунктирная рамка, а ограничение станет оранжевым. Вы так же увидите небольшое числовое значение на ограничении:

Если такое вдруг случилось непреднамеренно, то просто опустите вашу кнопку на 6 единиц вниз, используя стрелочки, или просто перетаскиваем мышки.

Наконец-то финальное перетаскивание с зажатым CTRL зеленой кнопки на желтую. При отпускании кнопки мышки на желтой кнопке появится меню, где вам нужно выбрать Left. Теперь, созданное ограничение говорит о том, что нам и нужно, а именно, что левые края зеленой и желтых кнопок, будут выровнены по левому краю желтой кнопки.

Запустите приложение и проверьте ваш горизонтальный и вертикальный виды:

Что дальше?

Дальше, вы можете продолжить изучать наши туториалы по мере их появления, а также, параллельно читать перевод официальной книги по языку программирования Swift. И, для более подробного изучения языка, вы можете пройти наши курсы!

Урок подготовил: Иван Акулов

Источник урока: http://www.raywenderlich.com/50317/beginning-auto-layout-tutorial-in-ios-7-part-1

Комментарии

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: