What is intrinsic content size and why care?

In this post I would like to touch a bit on a less known part of UIKit layout. The what and why of intrinsic content size.

Published: Jan. 27, 2021

I am sure you noticed, if you ever build UI with UIKit that with controls like UIButton or UILabel, that you need less constraints than for say a UIStackView or plain UIView. You can center UILabel vertically and horizontally and the layout is completely defined as AutoLayout is concerned. This will not work with UIView and the reason has all to do with intrinsic content size.

Intrinsic content size explained

I have to confess the "intrinsic" part is not at all intuitive for me as non-native English speaker and looking up definitions does not help either. However for UIKit purposes we can redefine intrinsic content size as "ideal content size".

This is basically the size the UI control in question would like to occupy. This makes a lot of sense for UILabel since its size is based on its textual content. The same goes for UIButton. These controls have some sense how much screen space they need to work correctly.

So if control has an intrinsic content size it means it will occupy this size unless told otherwise.

I hope this explains the need for less constraints when working with labels and buttons. And now let's turn to the more practical size.

Practical applications

Why even care? Because you can specify intrinsic content size for your own controls. This is great because you don't have to set up all the constraints and you can communicate your intended size.

For example if you are building custom base subclass for your buttons. Which you should btw to achieve visual consistency and have easier time changing your design. You can specify the intrinsic height to be at least 44 points and now you need to think about this when working with these buttons.

44 points is Apple's recommended height for touch targets even thou the vanilla UIButton ignores this and its intrinsic height is 30 points.

This could look something like this:

class BaseButton: UIButton {
    override var intrinsicContentSize: CGSize {
        let superSize = super.intrinsicContentSize
        return CGSize(width: superSize.width, height: 44)
    }
}

And now each button (assuming you use this BaseButton class) is at least 44 points tall without needing to specify the constraint.

I should also mention that this intrinsic size is not trivial to compute. Button has various kinds of internal insets the programer can configure, so when you can you should first get the super intrinsic size and modify as needed.

Another use case for intrinsic content size would be when creating custom separators. You can specify intrinsic height of say 0.5 points which means you don't have to remember to set this height via constraint each time you create the separator.

Only intrinsic height or width?

What about controls where only width or height makes sense for the intrinsic size? Don't worry, UIKit has got you covered.

There is noIntrinsicMetric static property on the UIView.

So for our hypothetical separator, we would use it like this:

class Separator: UIView {
    override var intrinsicContentSize: CGSize {
        return CGSize(width: UIView.noIntrinsicMetric, height: 0.5)
    }
}

Communicating intrinsic size changes

If you have custom control that has variable intrinsic size. Maybe because you are calculating it based on configuration of the subviews, there is an easy way to inform the layout system that the intrinsic case has changed.

Each UIView instance has invalidateIntrinsicContentSize() method used just for this purpose. So if your custom UIView subclass has for example UILabel which is used to calculate the intrinsic content size and you set new text, you should call invalidateIntrinsicContentSize to make sure your layout gets updated correctly.

Filip Němeček profile photo

WRITTEN BY

Filip Němeček @nemecek_f

iOS blogger and developer with interest in Python/Django. My recent projects include IndieAppsCatalog and ImpressKit.

iOS blogger and developer with interest in Python/Django. My recent projects include IndieAppsCatalog and ImpressKit.