716

I can't find a clear answer on Apple documentation regarding Cocoa Autolayout about the difference between content hugging and compression resistance.

Can somebody explain their usages and difference ?

David James
  • 2,430
  • 1
  • 26
  • 35
dmitrynikolaev
  • 8,994
  • 4
  • 30
  • 45
  • 71
    One of life's major mysterious is why they didn't call it simply "Expansion Resistance". The two qualities are nothing more than **"Expansion Resistance" and "Compression Resistance"**. The "hugging" terminology is insane. – Fattie Apr 11 '17 at 13:14
  • 4
    **If** you have too much room then `content-hugging`: would fight against having white space . It would just force the view to get around you. But **if** you don't have too much space, and instead have very little place then `content-compressions-resistance` would fight against your view from not being able to show all its content, e.g. labels would get truncated. – mfaani Nov 27 '17 at 05:03

10 Answers10

1407

A quick summary of the concepts:

  • Hugging => content does not want to grow
  • Compression Resistance => content does not want to shrink

Example:

Say you've got a button like this:

[       Click Me      ]

and you've pinned the edges to a larger superview with priority 500.

Then, if Hugging priority > 500 it'll look like this:

[Click Me]

If Hugging priority < 500 it'll look like this:

[       Click Me      ]

If the superview now shrinks then, if the Compression Resistance priority > 500, it'll look like this

[Click Me]

Else if Compression Resistance priority < 500, it could look like this:

[Cli..]

If it doesn't work like this then you've probably got some other constraints going on that are messing up your good work!

E.g. you could have it pinned to the superview with priority 1000. Or you could have a width priority. If so, this can be helpful:

Editor > Size to Fit Content

ncica
  • 7,015
  • 1
  • 15
  • 37
Snowcrash
  • 80,579
  • 89
  • 266
  • 376
  • 43
    What if hugging priority == 500? – bradley.ayers Jul 20 '13 at 10:36
  • 1
    I'd *assume* (but that's usually not a good idea) it'd be treated as >500 like typical rounding behavior. Haven't tested that though. – Joshua Nozzi Sep 02 '13 at 15:58
  • most likely you'll get "Unable to simultaneously satisfy constraints" warning in runtime – Max Desiatov Oct 07 '13 at 18:48
  • 9
    @bradley.ayers To MaxDesyatov's comment, that will only happen if you have conflicting constraints with Required priority (1000). If two lower-priority constraints conflict, the solution is ambiguous so the Auto Layout engine will just pick one valid solution and that's what you'll see (no warnings). Obviously this isn't good, because it's now up to the internal implementation of the Auto Layout engine to choose how your layout looks, and theoretically this could change from one iOS version to the next! – smileyborg Jan 10 '14 at 23:39
  • The content hugging priority default is 250, and the content compression resistance default is 750. So why use 500? – ZYiOS Apr 15 '15 at 02:13
  • The priorities are relative to others' priorities. And if all sub-views' constraints priorities are the same, it will be evaluated from left to right, or conforming to constraints' options. @bradley.ayers – DawnSong Jun 18 '15 at 11:08
  • I have a question, " you've pinned the edges to a larger superview with priority 500. " , which one of the superview's priority take effect with the subview's hugging priority, hugging priority or compression priority? – carl Jun 29 '15 at 08:38
  • Apple could have used "Expansion Resistance (or similar)" word instead of "Hugging". "Hugging" is too much confusing and irrelevant word with "Compression Resistance" in my opinion. – Nitesh Borad Jul 08 '16 at 06:43
  • example, the label we don't want shrinking, again, is the title label since the description label can be truncated if need be. To ensure our title label doesn't truncate its contents, we want to make sure its compression resistance priority is higher than our description label's compression resistance. – Ammar Mujeeb Apr 25 '17 at 07:07
  • Would it be correct to say: you no longer need to set the width/height and just set the leading, top constraints and then allow the intrinsic content size to kick in all while you also set your content hugging/content resistance? – mfaani Aug 14 '17 at 19:46
  • This is the best answer on the internet. I keep coming back to this answer when I run into problems with this, Even after a 10+ years of iOS development. – esbenr Mar 10 '21 at 08:00
317

Take a look at this video tutorial about Autolayout, they explain it carefully

enter image description here

onmyway133
  • 45,645
  • 31
  • 257
  • 263
  • 1
    @fatuhoku can you check again, this video is free – onmyway133 Jun 26 '14 at 14:58
  • 34
    Hugging vs. Resistance discussion starts at about the 13:15 point in the video. – Carl Smith Nov 07 '14 at 00:44
  • 1
    @onmyway133 this is perfect video, but unfortunately there is no example how Ray uses it. – Matrosov Oleksandr Dec 21 '14 at 19:39
  • @MatrosovAlexander I think a very practical example would be Dynamic cell height with Autolayout http://www.fantageek.com/1468/ios-dynamic-table-view-cells-with-varying-row-height-and-autolayout/ – onmyway133 Dec 22 '14 at 13:18
  • If I want a parent view expand or shrink with sub views, how should I do with these 2 situations? – carl Jun 29 '15 at 08:29
  • Yeah this was the point missing in accepted answer that if there are 2 or more uiviews then their CHCR priorties works in comparison to each-others priority numbers. Good Detail here: https://krakendev.io/blog/autolayout-magic-like-harry-potter-but-real – Ammar Mujeeb Apr 25 '17 at 07:13
  • 1
    He shows how to use the compression resistance at 18:05 – Brent Faust Apr 27 '17 at 14:52
  • so if an image has a lower content compression resistance...it will be scaled...to something smaller . But from what I see in your answer, the label (w/ lower content compression resistance), it won't be rescaled to a smaller font...rather the label would get truncated. Is there any way to make the label resize itself? or I guess that's normally not a good idea? – mfaani Aug 14 '17 at 18:44
  • It really helped to understand. – SThakur Jul 25 '19 at 12:31
282

enter image description here

source: @mokagio

Intrinsic Content Size - Pretty self-explanatory, but views with variable content are aware of how big their content is and describe their content's size through this property. Some obvious examples of views that have intrinsic content sizes are UIImageViews, UILabels, UIButtons.

Content Hugging Priority - The higher this priority is, the more a view resists growing larger than its intrinsic content size.

Content Compression Resistance Priority - The higher this priority is, the more a view resists shrinking smaller than its intrinsic content size.

Check here for more explanation: AUTO LAYOUT MAGIC: CONTENT SIZING PRIORITIES

SparkyRobinson
  • 1,502
  • 1
  • 15
  • 24
Balasubramanian
  • 5,274
  • 6
  • 33
  • 62
  • 1
    The illustration is nice but misleading to say the least. The top guy should say "I'm not gonna (let ME) grow". The child view defines on its own that it doesn't want to grow through it's content hugging behavior. There is no exogenic force (like the illustrated hands) that stop it from growing. That is a big difference. – Manuel Oct 03 '17 at 08:08
  • 19
    I'm up voting this just because I love the illustration. – James Bucanek Jan 17 '18 at 21:06
  • 5
    This is why I love Stack Overflow… Snowcrash's description plus this illustration by mokagio = best explanation of these properties anywhere (including Apple's own documentation). – Kal Jul 26 '18 at 02:48
  • @Manuel I don't think it's child view and parent view here. Rather the rectangle is the view and the person is the implicitly generated system constraint trying to achieve the desired behaviour (hugging or compression resistance) with set priority. So the illustration is still right. – pius Feb 05 '22 at 17:47
45

Let's say you have a button with the text, "Click Me". What width should that button be?

First, you definitely don't want the button to be smaller than the text. Otherwise, the text would be clipped. This is the horizontal compression resistance priority.

Second, you don't want the button to be bigger than it needs to be. A button that looked like this, [          Click Me          ], is obviously too big. You want the button to "hug" its contents without too much padding. This is the horizontal content hugging priority. For a button, it isn't as strong as the horizontal compression resistance priority.

Bridger Maxwell
  • 2,081
  • 1
  • 19
  • 25
21

If view.intrinsicContentSize.width != NSViewNoIntrinsicMetric, then auto layout creates a special constraint of type NSContentSizeLayoutConstraint. This constraint acts like two normal constraints:

  • a constraint requiring view.width <= view.intrinsicContentSize.width with the horizontal hugging priority, and
  • a constraint requiring view.width >= view.intrinsicContentSize.width with the horizontal compression resistance priority.

In Swift, with iOS 9's new layout anchors, you could set up equivalent constraints like this:

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)

Similarly, if view.intrinsicContentSize.height != NSViewNoIntrinsicMetric, then auto layout creates an NSContentSizeLayoutConstraint that acts like two constraints on the view's height. In code, they would look like this:

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)

You can see these special NSContentSizeLayoutConstraint instances (if they exist) by printing view.constraints after layout has run. Example:

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
  • 375,296
  • 67
  • 796
  • 848
  • 1
    should it not be: let verticalCompression = view.heightAnchor.constraint( greaterThanOrEqualToConstant: view.intrinsicContentSize.height) – mc_plectrum Jun 08 '17 at 07:04
  • 1
    Yes, I made a copy/paste error. I have corrected it. Thank you for letting me know. – rob mayoff Jun 08 '17 at 15:10
15

Content Hugging and Content Compression Resistence Priorities work for elements which can calculate their size intrinsically depending upon the contents which are coming in.

From Apple docs:

enter image description here

dev gr
  • 2,409
  • 1
  • 21
  • 33
  • I'm confused. For a textView that doesn't have scrolling enabled. Does that mean per user typing the intrinsic size would change? – mfaani Aug 15 '17 at 14:08
  • @Honey I think with correct constraints set and scrolling disabled, text view should be able to tell intrinsic height. – dev gr Aug 16 '17 at 06:07
  • That didn't answer my question. You mean if I type a lot a lot, more than the current size of the textView....does the textView expand automatically and change the intrinsic size? – mfaani Aug 16 '17 at 09:58
  • Try it yourself. Give textview a fixed width and disable the scroll and check for desired behaviour. Refer https://stackoverflow.com/a/21287306/1526629 for more answers. – dev gr Aug 16 '17 at 10:08
14

The Content hugging priority is like a Rubber band that is placed around a view. The higher the priority value, the stronger the rubber band and the more it wants to hug to its content size. The priority value can be imagined like the "strength" of the rubber band

And the Content Compression Resistance is, how much a view "resists" getting smaller The View with higher resistance priority value is the one that will resist compression.

Naishta
  • 11,885
  • 4
  • 72
  • 54
0

contentCompressionResistancePriority – The view with the lowest value gets truncated when there is not enough space to fit everything’s intrinsicContentSize

contentHuggingPriority – The view with the lowest value gets expanded beyond its intrinsicContentSize when there is leftover space to fill

ahmed
  • 540
  • 2
  • 18
  • I always remember this now and ever since have had no issues. Resistance priority is important when there is not enough space to fit elements. Hugging priority is important when there is too much space. – JCutting8 Jul 25 '21 at 11:46
0

When we thinking about these two priorities, we need to consider the conditions.

When the space is enough for two or more widgets, we consider hugging priority, the priority is less, it will take the surplus space, and other widgets only take the Intrinsic Content Size.

When the space is not enough for widgets, we consider the Content Compression Resistance as well.

BollMose
  • 3,002
  • 4
  • 32
  • 41
0

iOS AutoLayout - Intrinsic Content Size And Content Hugging & Content Compression Resistence Priority(CHCR)

[AutoLayout]

Intrinsic Content Size

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

AutoLayout uses Intrinsic Content Size to create implicit constraint(width and/or height)

Intrinsic Content Size - tells how much space(width and/or height) is needed to show a full content.

Not all views have an intrinsic content size

UIView and NSView - No intrinsic content size

  • But actually - UIView object doesn't have it and UIView class has intrinsicContentSize variable which is/can be overrode by subclass. For example UILabel has it's own realization which is based on text and font attributes
  • UIView subclass uses default realisation with UIView.noIntrinsicMetric (-1)

pseudocode:

import UIKit

class UIView {
   override var intrinsicContentSize: CGSize {
       return CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
   }
}
  • when you need to recalculate intrinsicContentSize and redraw it - call view.invalidateIntrinsicContentSize()

  • intrinsicContentSize vs sizeToFit(). intrinsicContentSize is for AutoLayout, sizeToFit() is for Frame-based.

    • call view.sizeToFit()
    • override view.sizeThatFits(_ size: CGSize). size usually is view.bounds.size

Content Hugging & Content Compression Resistence Priority(CHCR)

Every view has a CHCR priority for each dimension(horizontal, vertical) but it is applied only view with intrinsicContentSize. Also it has an impact on constraint priority

Content Hugging Priority(CHP)(default value is 251)

Prevent expanding. Higher priority - prevent view to be bigger then Intrinsic Content Size.

Content Compression Resistence Priority(CRP)(default value is 750)

Prevent collapsing. Higher priority - prevent view to be smaller then Intrinsic Content Size.

Experiments:

Two UILabels(Label 1, Label 2), which is layout one by one horizontally

  1. Warning:
Content Priority Ambiguity
Decrease horizontal hugging...
  1. To fix it using Content Hugging Priority
  1. Warning:
Content Priority Ambiguity
Decrease horizontal compression resistance...
  1. To fix it using Content Compression Resistence Priority
  1. If you want to show both Labels you can use width constraint which has bigger priority(1000 by default)
yoAlex5
  • 29,217
  • 8
  • 193
  • 205