В iOS, каковы различия между полями, вставками краев, вставками контента, строками выравнивания, полями макета, якорями...?

Кажется, есть несколько различных вариантов / терминов, и люди в сообществе iOS используют в отношении макета (например, UIEdgeInsets - это тип, но иногда я слышу / читаю "установить вкладки" или поля макета или руководства по макету).

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

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

3 ответа

Будучи предложителем щедрости... Я бы сказал, что большая часть моего замешательства возникла из-за неправильного понимания UILayoutGuide учебный класс. Это является ключевым, но также очень простым.

Позвольте мне сначала представить проблему:

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

Затем вам нужно было создать чистые UIViews и добавить их в качестве ваших подпредставлений, а затем добавить к ним свои ограничения, как показано ниже:


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

Создание макетов

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

  1. Создание нового руководства по компоновке.
  2. Добавьте руководство по компоновке в представление, вызвав его addLayoutGuide(_:) метод.
  3. Определите положение и размер руководства по макету, используя Auto Layout. Вы можете использовать эти направляющие для определения пространства между элементами в макете. В следующем примере показаны направляющие макета, используемые для определения равного расстояния между сериями видов.

шаги:

let space1 = UILayoutGuide()
view.addLayoutGuide(space1)

let space2 = UILayoutGuide()
view.addLayoutGuide(space2)

space1.widthAnchor.constraintEqualToAnchor(space2.widthAnchor).active = true
saveButton.trailingAnchor.constraintEqualToAnchor(space1.leadingAnchor).active = true
cancelButton.leadingAnchor.constraintEqualToAnchor(space1.trailingAnchor).active = true
cancelButton.trailingAnchor.constraintEqualToAnchor(space2.leadingAnchor).active = true
clearButton.leadingAnchor.constraintEqualToAnchor(space2.trailingAnchor).active = true

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

Три интересные заметки:

  1. Если вы используете "просмотр иерархии отладки", вы увидите больше экземпляров UILayoutGuide
  2. Так же, как и UIView, экземпляр UILayoutGuide имеет все виды якорей
  3. Что касается того, почему бы не просто создать фиктивные UIViews и пройти через создание UILayoutGuides: "Существует несколько затрат, связанных с добавлением фиктивных представлений в вашу иерархию представлений. Во-первых, это затраты на создание и поддержание самого представления. Во-вторых, фиктивное представление является полноправным членом иерархии представления, что означает, что он добавляет издержки к каждой задаче, которую выполняет иерархия. Хуже всего то, что невидимое фиктивное представление может перехватывать сообщения, предназначенные для других представлений, вызывая проблемы, которые очень трудно найти ".

Для получения дополнительной информации см. Документацию.


topLayoutGuide против safeAreaLayoutGuide

topLayoutGuide (устарело)

Это не рекомендуется для, но в целях обучения: A UIViewController имеет 2 пустышки. 1 свойство в верхней части имени topLayoutGuide и еще одно свойство в нижней части bottomLayoutGuide, Сам ViewController не имеет направляющих для левой / передней или правой / задней сторон. Оба из них являются примером UILayoutGuide

если ограничен view.topAnchor т.е.

tableView.topAnchor.constraint(equalTo: view.topAnchor)

tableView не начинается с нижней части панели навигации

если ограничено topLayoutGuide.bottomAnchor то есть:

tableView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor)

tableView начинается с нижней части панели навигации

И в зависимости от вашего макета вы можете захотеть, чтобы ваш контент был размытым ниже панели навигации.

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

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

safeAreaLayoutGuide

с iOS11

Apple устарела topLayoutGuide & bottomLayoutGuide, Таким образом, вместо 2-х пустышек, теперь у вас есть 1 пустышка с именем safeAreaLayoutGuide на экземпляре UIView. UIViewController больше не имеет ничего подобного... Визуальное сравнение скопировано с useyourloaf:

примечание: если вы используете раскадровки, то выравнивание ваших представлений с topLayoutGuide или top из safeAreaLayoutGuide будет отображать то же самое. Если вы не используете раскадровки (делайте это программно), вам придется танцевать между iOS11 и LessThaniOS11 и иметь 2 разные версии кода.

Для больше на safeAreaLayoutGuide Я настоятельно рекомендую вам установить статью Apple: Позиционирование контента относительно безопасной зоны


layoutMarginsGuide

  • UIView имеет только 1 пустышку. Свойство называется layoutMarginsGuide, Но в отличие от UIViewController он не сидит сверху или снизу. Он просто расположен в центре с 8-точечным заполнением / вставкой (со всех четырех сторон) в UIView, Так где это полезно?: Вы бы использовали это, если не хотите, чтобы ваш textView был ограничен краями экземпляра UIView. Это улучшит опыт чтения. Или вместо того, чтобы ограничить кнопку ведущим якорем ее суперпредставления и сделать его уродливым, вы добавляете 8 точек к якору... т.е. ограничиваете кнопку ведущим якорем, а затем добавляете 8 постоянных точек. Вычеркнутый текст, на самом деле, где вы будете использовать readableContentGuide, layoutMarginsGuide полезно, если вы не хотите, чтобы ваша кнопка или ярлык были привязаны к краю суперпредставления

    someButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8)
    

    Но подождите, есть более простой способ. Просто используйте рекомендованную маржу Apple, т.е. используйте:

    someButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor)
    

    Также см. Пример, приведенный в документации. Хороший учебник Raywenderlich можно найти здесь


readableContentGuide

  • Немного отличается от layoutMarginGuide, Оба являются свойствами UIView. Иногда они идентичны, иногда нет. Его целью является:

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

    Чтобы узнать больше об этом моменте из WWDC: построение адаптивного макета и этот замечательный учебник useyourloaf.

    На iPhone 7 Plus в портретной ориентации читаемые направляющие содержимого такие же, как и направляющие полей представления, но в альбомной ориентации больше пространства с обеих сторон текстового представления. На iPad в альбомной ориентации белое пространство значительно увеличивается.

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

    От RayWenderlich

На изображении ниже голубой привязан к layoutMarginGuide, но синий привязан к readableContentGuide:


UIEdgeInsets

  • Если вы хотите изменить свой layoutMarginsGuide то есть изменить его с 8 до 16 баллов, то вы должны изменить layoutMargins значение, а затем layoutMarginsGuide Якоря будут автоматически обновляться. UIEdgeInsets это просто тип вашего layoutMargins, layoutMargins это имя свойства UIView учебный класс

    someview.layoutMargins = UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50)
    

    Единственное место, где я нашел этот код ☝️, чтобы его эффект был внутри viewDidLayoutSubviews . Подробнее см. Здесь

  • якоря не особенные. Они являются самым дальним краем любого UIView/UILayoutGuide. И экземпляры UIView и UIlayoutGuide имеют это. ВСЕ, что вы ограничиваете, в конечном итоге ограничивается использованием якорей, это просто вопрос того, к каким якорям сущности вы привязываете это. Это может быть safeAreaLayoutGuide Якорь, это может быть layoutMarginGuide Якорь, это может быть topLayoutGuide Якорь это может быть view Якорь (хотя вы также можете просто привязать ваш heightAnchor к 50, так что в этом случае другого якоря не будет)

    Отличное визуальное сравнение layoutMarginsGuide а также Anchors можно найти из этого ответа. Это сделано с использованием раскадровок, чтобы облегчить понимание.

  • contentInsets действительно не имеет ничего общего с другими. Для более подробной информации смотрите эту статью


Заключение

Быть в безопасности и быть уверенным, что все в вашем распоряжении. safeAreaLayoutGuide, Если вы хотите использовать предоставленные системой поля, чтобы иметь лучшее расположение видов или иметь некоторые отступы, используйте layoutMarginGuide, если вы хотите сделать вещи более читабельными readableContentGuide,

readableContentGuide размер всегда меньше или равен layoutMarginGuide,
layoutMarginGuide размер всегда меньше или равен safeAreaLayoutGuide

layoutMargins очень похоже на отступы CSS. safeAreaLayoutGuide похож на границы CSS. Я не знаю, есть ли какой-либо CSS-эквивалент для readableContentGuide


ContentInset и ContentOffset

Они предназначены для scrollViews и в некоторой степени не связаны с остальной частью ответа. Что за что contentInset & contentOffset смотрите, пожалуйста, этот момент из WWDC 2018: UIKit: приложения для любого размера и формы. Видео очень простое. Также см. Ответ Картика ниже. При этом важно знать, как работает scrollView, и понимать, что contentSize есть, иначе было бы сложно. Для больше на contentSize и scrollView см . ответ Vacawama здесь

Я надеюсь, что вы получите информацию по следующим ссылкам / фотографиям.

По ссылкам ниже вы сможете вывести необходимую информацию о параметрах макета.

  1. выравнивание выравнивание

  2. вставка и смещение содержимого, пример 2 содержание вставок контент оффест другой пример

  3. поля поля

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

Что касается того, что является лучшим способом реализации макета, когда у вас есть несколько методов / опций, которые работают... это действительно вопрос стиля / мнения. Я бы сосредоточился на следующих критериях, чтобы прийти к решению:

  1. Подумайте об исключении опций, которые сложнее всего поддерживать / отлаживать / понимать
    • Представьте, что кто-то новенький присоединился к вашей команде или кто-то унаследовал ваш код - какую реализацию им будет трудно отлаживать и почему?
  2. Подумайте об исключении опций, которые делают макет более сложным для изменения / расширения / редактирования
  3. Подумайте об исключении опций, которые несовместимы с остальной частью приложения (этот вид восходит к первому пункту)
  4. Подумайте об исключении вариантов, противоречащих намерениям Apple (см. Документацию /WWDC, чтобы понять их намерения).

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

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


Некоторые выдержки из документации Apple для классов, которые описаны в вопросе:

На UILayoutGuide:

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

...

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

На макете поля:

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

На directionalLayoutMargins:

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

На contentInset:

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

На вершине Якорь:

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

На NSLayoutAnchor

Используйте эти ограничения, чтобы программно определить свой макет с помощью Auto Layout. Вместо непосредственного создания объектов NSLayoutConstraint начните с объекта UIView, NSView или UILayoutGuide, который вы хотите ограничить, и выберите одно из свойств привязки этого объекта. Эти свойства соответствуют основным значениям NSLayoutConstraint.Attribute, используемым в Auto Layout, и предоставляют соответствующий подкласс NSLayoutAnchor для создания ограничений для этого атрибута. Используйте методы привязки для построения вашего ограничения.

Другие вопросы по тегам