Какао Autolayout: обнимание контента против приоритета сопротивления сжатия контента

Я не могу найти четкого ответа в документации Apple, касающейся Autolayout Cocoa о разнице между объятием контента и сопротивлением сжатию.

Может кто-нибудь объяснить их обычаи и разницу?

10 ответов

Решение

Краткое резюме понятий:

  • Обниматься => контент не хочет расти
  • Сопротивление сжатию => контент не хочет сжиматься

и пример:

Скажем, у вас есть кнопка, как это:

[       Click Me      ]

и вы прикрепили края к большему суперпредставлению с приоритетом 500.

Тогда, если приоритет Hugging> 500, это будет выглядеть так:

[Click Me]

Если приоритет Hugging < 500, это будет выглядеть так:

[       Click Me      ]

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

[Click Me]

Иначе, если приоритет сопротивления сжатию < 500, он может выглядеть так:

[Cli..]

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

Например, вы можете прикрепить его к суперпредставлению с приоритетом 1000. Или вы можете иметь приоритет ширины. Если это так, это может быть полезно:

Редактор> Размер по размеру содержимого

Взгляните на этот видеоурок об Autolayout, они объясняют это внимательно

введите описание изображения здесь

Источник: @mokagio

Внутренний размер контента. Довольно понятен, но представления с переменным контентом знают, насколько велик их контент, и описывают размер своего контента с помощью этого свойства. Некоторыми очевидными примерами представлений с внутренними размерами контента являются UIImageViews, UILabels, UIButtons.

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

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

Проверьте здесь для более подробного объяснения: МАГИЯ АВТОМАТИЧЕСКОЙ СХЕМЫ: ПРИОРИТЕТЫ РАЗМЕРА КОНТЕНТА

Допустим, у вас есть кнопка с текстом "Нажми меня". Какой ширины должна быть эта кнопка?

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

Во-вторых, вы не хотите, чтобы кнопка была больше, чем она должна быть. Кнопка, которая выглядела следующим образом, [          Click Me          ], очевидно, слишком велика. Вы хотите, чтобы кнопка "обнимала" ее содержимое без слишком большого заполнения. Это горизонтальный приоритет содержания контента. Для кнопки это не так сильно, как приоритет сопротивления горизонтальному сжатию.

Если view.intrinsicContentSize.width != NSViewNoIntrinsicMetric, тогда автоматическое расположение создает специальное ограничение типа NSContentSizeLayoutConstraint, Это ограничение действует как два нормальных ограничения:

  • ограничение, требующее view.width <= view.intrinsicContentSize.width с приоритетом горизонтального объятия, и
  • ограничение, требующее view.width >= view.intrinsicContentSize.width с приоритетом сопротивления горизонтальному сжатию.

В Swift с новыми привязками макета в iOS 9 вы можете установить эквивалентные ограничения, например:

let horizontalHugging = view.widthAnchor.constraint(
    lessThanOrEqualToConstant: view.intrinsicContentSize.width)
horizontalHugging.priority = view.contentHuggingPriority(for: .horizontal)

let horizontalCompression = view.widthAnchor.constraint(
    greaterThanOrEqualToConstant: view.intrinsicContentSize.width)
horizontalCompression.priority = view.contentCompressionResistancePriority(for: .horizontal)

Точно так же, если view.intrinsicContentSize.height != NSViewNoIntrinsicMetric, а затем автоматическое расположение создает NSContentSizeLayoutConstraint это действует как два ограничения на высоту представления. В коде они будут выглядеть так:

let verticalHugging = view.heightAnchor.constraint(
    lessThanOrEqualToConstant: view.intrinsicContentSize.height)
verticalHugging.priority = view.contentHuggingPriority(for: .vertical)

let verticalCompression = view.heightAnchor.constraint(
    greaterThanOrEqualToConstant: view.intrinsicContentSize.height)
verticalCompression.priority = view.contentCompressionResistancePriority(for: .vertical)

Вы можете увидеть эти специальные NSContentSizeLayoutConstraint экземпляры (если они существуют) путем печати view.constraints после запуска макета Пример:

label.constraints.forEach { print($0) }

// Output:
<NSContentSizeLayoutConstraint:0x7fd82982af90 H:[UILabel:0x7fd82980e5e0'Hello'(39)] Hug:250 CompressionResistance:750>
<NSContentSizeLayoutConstraint:0x7fd82982b4f0 V:[UILabel:0x7fd82980e5e0'Hello'(21)] Hug:250 CompressionResistance:750>

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

Из документов Apple:

введите описание изображения здесь

Content hugging priority это как резиновая полоса, которая размещается вокруг вида. Чем выше значение приоритета, тем сильнее резиновая полоса и тем больше она хочет обнять свой размер содержимого. Значение приоритета можно представить как "прочность" резиновой ленты

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

iOS AutoLayout — внутренний размер контента, охват контента и приоритет устойчивости к сжатию контента (CHCR)

[Автомакет]

Внутренний размер контента

      Intrinsic Content Size -> Constraint -> AutoLayout engine -> draw

AutoLayoutиспользуетIntrinsic Content Sizeсоздать неявное ограничение (ширину и/или высоту)

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

Не все представления имеют собственный размер контента.

UIView и NSView — нет внутреннего размера контента

  • Но на самом деле у объекта его нет, а у класса есть переменная, которая может быть переопределена подклассом. НапримерUILabelимеет собственную реализацию, основанную на атрибутах текста и шрифта.
  • UIViewподкласс использует реализацию по умолчанию с UIView.noIntrinsicMetric (-1)

псевдокод:

      import UIKit

class UIView {
   override var intrinsicContentSize: CGSize {
       return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
   }
}
  • когда понадобится его пересчитать и перерисовать - звонитеview.invalidateIntrinsicContentSize()

  • против . для AutoLayout,sizeToFit()предназначен для фреймов.

    • вызовview.sizeToFit()
    • переопределитьview.sizeThatFits(_ size: CGSize). размер обычно равен view.bounds.size

Приоритет устойчивости к сжатию контента и сжатию контента (CHCR)

Каждое представление имеет приоритет CHCR для каждого измерения (горизонтального, вертикального), но применяется только вид сintrinsicContentSize. Также это влияет на приоритет ограничения.

Приоритет захвата контента (CHP)(значение по умолчанию — 251)

Предотвратить расширение. Более высокий приоритет — запретить просмотр, превышающий внутренний размер контента.

Приоритет устойчивости к сжатию содержимого (CRP)(значение по умолчанию — 750)

Предотвратить обрушение. Более высокий приоритет — запретить представление меньше внутреннего размера контента.

Эксперименты:

Две UILabels(Label 1, Label 2), которые располагаются одна за другой по горизонтали.

  1. Предупреждение:
      Content Priority Ambiguity
Decrease horizontal hugging...
  1. Чтобы исправить это, используйте приоритет захвата контента.
  1. Предупреждение:
      Content Priority Ambiguity
Decrease horizontal compression resistance...
  1. Чтобы исправить это, используйте приоритет устойчивости к сжатию контента.
  1. Если вы хотите отобразить обе метки, вы можете использовать ограничение ширины, которое имеет больший приоритет (по умолчанию 1000).

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

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

Когда места для виджетов не хватает , мы рассматриваемContent Compression Resistanceтакже.

contentCompressionResistancePriority - представление с наименьшим значением усекается, когда недостаточно места для размещения всегоintrinsicContentSize

contentHuggingPriority - представление с наименьшим значением расширяется за пределыintrinsicContentSize когда есть оставшееся место для заполнения

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