Cocoa Autolayout: étreinte de contenu vs priorité de résistance à la compression de contenu

643

Je ne trouve pas de réponse claire sur la documentation d'Apple concernant Cocoa Autolayout concernant la différence entre l'étirement du contenu et la résistance à la compression.

Quelqu'un peut-il expliquer ses usages et sa différence?

dmitrynikolaev
la source
49
L'un des mystères majeurs de la vie est pourquoi ils ne l'ont pas appelé simplement "Expansion Resistance". Les deux qualités ne sont rien de plus que "Résistance à l'expansion" et "Résistance à la compression" . La terminologie «étreindre» est folle.
Fattie
3
Si vous avez trop de place, alors content-hugging: vous vous battez contre un espace blanc. Cela forcerait simplement la vue à vous contourner. Mais si vous n'avez pas trop d'espace, et que vous avez à la place très peu de place, alors vous vous content-compressions-resistancebattriez contre votre vue de ne pas pouvoir afficher tout son contenu, par exemple, les étiquettes seraient tronquées.
Honey

Réponses:

1319

Un bref résumé des concepts:

  • Étreindre => le contenu ne veut pas grandir
  • Résistance à la compression => le contenu ne veut pas rétrécir

Exemple:

Disons que vous avez un bouton comme celui-ci:

[       Click Me      ]

et vous avez épinglé les bords à une vue d'ensemble plus grande avec la priorité 500.

Ensuite, si la priorité à l'étreinte> 500, cela ressemblera à ceci:

[Click Me]

Si la priorité à l'étreinte <500, cela ressemblera à ceci:

[       Click Me      ]

Si la vue d'ensemble rétrécit maintenant, si la priorité de résistance à la compression> 500, cela ressemblera à ceci

[Click Me]

Sinon, si la priorité à la résistance à la compression est <500, cela pourrait ressembler à ceci:

[Cli..]

Si cela ne fonctionne pas ainsi, vous avez probablement d'autres contraintes qui gâchent votre bon travail!

Par exemple, vous pouvez l'épingler à la vue d'ensemble avec la priorité 1000. Ou vous pouvez avoir une priorité de largeur. Si oui, cela peut être utile:

Editeur> Ajuster au contenu

Snowcrash
la source
37
Et si vous étreigniez la priorité == 500?
bradley.ayers
1
Je suppose (mais ce n'est généralement pas une bonne idée) qu'il serait traité comme> 500 comme un comportement d'arrondi typique. Je n'ai pas testé cela cependant.
Joshua Nozzi
très probablement, vous obtiendrez l'avertissement "Impossible de satisfaire simultanément les contraintes" lors de l'exécution
Max Desiatov
8
@ bradley.ayers Pour le commentaire de MaxDesyatov, cela ne se produira que si vous avez des contraintes conflictuelles avec la priorité requise (1000). Si deux contraintes de priorité inférieure entrent en conflit, la solution est ambiguë, de sorte que le moteur de disposition automatique ne choisira qu'une seule solution valide et c'est ce que vous verrez (aucun avertissement). Évidemment, ce n'est pas bon, car c'est maintenant à l'implémentation interne du moteur de mise en page automatique de choisir l'apparence de votre mise en page, et théoriquement, cela pourrait changer d'une version iOS à l'autre!
smileyborg
La priorité par défaut du contenu est de 250 et la résistance de compression du contenu par défaut est 750. Alors pourquoi utiliser 500?
ZYiOS
292

Jetez un oeil à ce tutoriel vidéo sur Autolayout , ils l'expliquent soigneusement

entrez la description de l'image ici

onmyway133
la source
1
@fatuhoku pouvez-vous vérifier à nouveau, cette vidéo est gratuite
onmyway133
31
Étreindre vs résistance commence à environ 13h15 dans la vidéo.
Carl Smith
1
@ onmyway133 c'est une vidéo parfaite, mais malheureusement il n'y a pas d'exemple comment Ray l'utilise.
Matrosov Alexander
@MatrosovAlexander Je pense qu'un exemple très pratique serait la hauteur de cellule dynamique avec Autolayout fantageek.com/1468/…
onmyway133
1
Il montre comment utiliser la résistance à la compression à 18h05
Brent Faust
187

entrez la description de l'image ici

source: @mokagio

Taille de contenu intrinsèque - assez explicite, mais les vues avec un contenu variable sont conscientes de la taille de leur contenu et décrivent la taille de leur contenu via cette propriété. UIImageViews, UILabels, UIButtons sont des exemples évidents de vues qui ont des tailles de contenu intrinsèques.

Content Hugging Priority - Plus cette priorité est élevée, plus une vue résiste à devenir plus grande que sa taille de contenu intrinsèque.

Priorité de résistance à la compression du contenu - Plus cette priorité est élevée, plus une vue résiste à rétrécir plus petite que sa taille de contenu intrinsèque.

Cochez ici pour plus d'explications: MAGIE DE MISE EN PAGE AUTOMATIQUE: PRIORITÉS DE TAILLE DU CONTENU

Balasubramanian
la source
L'illustration est sympa mais trompeuse pour le moins. Le meilleur gars devrait dire "je ne vais pas (laisser ME) grandir". La vue enfant définit d'elle-même qu'elle ne souhaite pas se développer à travers son comportement de contournement de contenu. Il n'y a aucune force exogène (comme les mains illustrées) qui l'empêche de se développer. Cela fait une grande différence.
Manuel
6
Je vote pour ça juste parce que j'aime l'illustration.
James Bucanek
3
C'est pourquoi j'aime Stack Overflow… La description de Snowcrash plus cette illustration par mokagio = meilleure explication de ces propriétés n'importe où (y compris la propre documentation d'Apple).
Kal
40

Disons que vous avez un bouton avec le texte "Click Me". Quelle largeur doit avoir ce bouton?

Tout d'abord, vous ne voulez certainement pas que le bouton soit plus petit que le texte. Sinon, le texte serait tronqué. Il s'agit de la priorité de résistance à la compression horizontale.

Deuxièmement, vous ne voulez pas que le bouton soit plus grand qu'il ne devrait l'être. Un bouton qui ressemblait à ceci, [Click Me], est évidemment trop gros. Vous voulez que le bouton "embrasse" son contenu sans trop de remplissage. Il s'agit de la priorité d'élargissement du contenu horizontal. Pour un bouton, il n'est pas aussi fort que la priorité de résistance à la compression horizontale.

Bridger Maxwell
la source
19

Si view.intrinsicContentSize.width != NSViewNoIntrinsicMetric, la mise en page automatique crée une contrainte de type spéciale NSContentSizeLayoutConstraint. Cette contrainte agit comme deux contraintes normales:

  • une contrainte nécessitant view.width <= view.intrinsicContentSize.widthavec la priorité de calage horizontal, et
  • une contrainte nécessitant view.width >= view.intrinsicContentSize.widthavec la priorité de résistance à la compression horizontale.

Dans Swift, avec les nouvelles ancres de mise en page d'iOS 9, vous pouvez configurer des contraintes équivalentes comme ceci:

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)

De même, si view.intrinsicContentSize.height != NSViewNoIntrinsicMetric, la mise en page automatique crée un NSContentSizeLayoutConstraintqui agit comme deux contraintes sur la hauteur de la vue. Dans le code, ils ressembleraient à ceci:

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)

Vous pouvez voir ces NSContentSizeLayoutConstraintinstances spéciales (si elles existent) en imprimant view.constraintsaprès l'exécution de la mise en page. Exemple:

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>
rob mayoff
la source
1
si ce n'est pas le cas: laissez verticalCompression = view.heightAnchor.constraint (GreaterThanOrEqualToConstant: view.intrinsicContentSize.height)
mc_plectrum
1
Oui, j'ai fait une erreur de copier / coller. Je l'ai corrigé. Merci de me l'avoir dit.
rob mayoff
15

Les priorités de contention de contenu et de compression de contenu fonctionnent pour les éléments qui peuvent calculer leur taille intrinsèquement en fonction du contenu entrant.

Depuis les documents Apple :

entrez la description de l'image ici

dev gr
la source
plus1 pour l'image (Y)
Noor Ali Butt
Je suis confus. Pour une TextView dont le défilement n'est pas activé. Cela signifie-t-il que chaque utilisateur saisissant la taille intrinsèque changerait?
Honey
@Honey Je pense qu'avec les contraintes correctes définies et le défilement désactivé, la vue texte devrait être capable de dire la hauteur intrinsèque.
dev gr
Cela n'a pas répondu à ma question. Vous voulez dire que si je tape beaucoup, plus que la taille actuelle de textView .... le textView se développe-t-il automatiquement et change-t-il la taille intrinsèque?
Honey
Essayez-le vous-même. Donnez à textview une largeur fixe et désactivez le défilement et vérifiez le comportement souhaité. Consultez stackoverflow.com/a/21287306/1526629 pour plus de réponses.
dev gr
11

C'est Content hugging prioritycomme un élastique qui est placé autour d'une vue. Plus la valeur de priorité est élevée, plus la bande élastique est forte et plus elle souhaite s'adapter à la taille de son contenu. La valeur de priorité peut être imaginée comme la "résistance" de l'élastique

Et Content Compression Resistancec'est à quel point une vue «résiste» à devenir plus petite La vue avec une valeur de priorité de résistance plus élevée est celle qui résistera à la compression.

Naishta
la source