Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set a custom view's intrinsic content size in Swift?

Background

I am making a vertical label to use with traditional Mongolian script. Before I was just rotating a UILabel but there were some performance issues and other complications with this. Now I am working on making a label from scratch. However, I need the vertical label to tell auto layout when its height adjusts (based on string length).

What I have read

I read the Intrinsic Content Size and Views with Intrinsic Content Size documentation. These were more about how to use it, though, and not how to define it in a custom view.

Searching for "ios intrinsic content size for a custom view" only gives me

  • Proper usage of intrinsicContentSize and sizeThatFits: on UIView Subclass with autolayout

in Stack Overflow. This particular question didn't even need intrinsic content size because their view was just an assembly of standard views.

What I am trying

What I am trying is my answer below. I am adding this Q&A pair so that it won't take other people as long to find the answer as it took me with the search keywords that I used.

like image 930
Suragch Avatar asked Mar 29 '16 09:03

Suragch


People also ask

How does a view's intrinsic content size aid in auto layout?

In general, the intrinsic content size simplifies the layout, reducing the number of constraints you need. However, using the intrinsic content size often requires setting the view's content-hugging and compression-resistance (CHCR) priorities, which can add additional complications.

What is intrinsic size in Swift?

Most views have an intrinsic content size, which refers to the amount of space the view needs for its content to appear in an ideal state. For example, the intrinsic content size of a UILabel will be the size of the text it contains using whatever font you have configured it to use.

What is content size and intrinsic content size in IOS?

Intrinsic content size is information that a view has about how big it should be based on what it displays. For example, a label's intrinsic content size is based on how much text it is displaying. In your case, the image view's intrinsic content size is the size of the image that you selected.

Is UIStackView intrinsic content size?

Each of the elements has it's own intrinsicContentSize so it should be possible for the UIStackView to provide its own intrinsicContentSize . The documentation states that the spacing is used as a minimum spacing. The intrinsicContentSize.


2 Answers

Setting the intrinsic content size of a custom view lets auto layout know how big that view would like to be. In order to set it, you need to override intrinsicContentSize.

override var intrinsicContentSize: CGSize {    return CGSize(width: x, height: y) } 

Then call

invalidateIntrinsicContentSize() 

Whenever your custom view's intrinsic content size changes and the frame should be updated.

Notes

  • Swift 3 update: Easier Auto Layout: Coding Constraints in iOS 9
  • Just because you have the intrinsic content size set up in your custom view doesn't mean it will work as you expect. Read the documentation for how to use it, paying special attention to Content-Hugging and Compression-Resistance.
  • Thanks also to this Q&A for putting me on the right track: How can I add padding to the intrinsic content size of UILabel?
  • Thanks also to this article and the documentation for help with invalidateIntrinsicContentSize().
like image 184
Suragch Avatar answered Oct 02 '22 08:10

Suragch


Example of a "view with intrinsic height" ...

@IBDesignable class HView: UIView {      @IBInspectable var height: CGFloat = 100.0      override var intrinsicContentSize: CGSize {         return CGSize(width: 99, height: height)         // if using in, say, a vertical stack view, the width is ignored     }      override func prepareForInterfaceBuilder() {          invalidateIntrinsicContentSize()     } } 

enter image description here

which you can set as an inspectable

enter image description here

Since it has an intrinsic height, it can (for example) be immediately inserted in a stack view in code:

stack?.insertArrangedSubview(HView(), at: 3) 

In contrast, if it was a normal view with no intrinsic height, you'd have to add a height anchor or it would crash:

let v:UIView = HView() v.heightAnchor.constraint(equalToConstant: 100).isActive = true stack?.insertArrangedSubview(v, at: 3) 

Note that in ...

the important special case of a stack view:

  • you set only ONE anchor (for vertical stack view, the height; for horizontal the width)

so, setting the intrinsic height works perfectly, since:

  • the intrinsic height indeed means that the height anchor specifically will be set automatically if needed.

Remembering that in all normal cases of a subview, many other anchors are needed.

like image 42
Fattie Avatar answered Oct 02 '22 08:10

Fattie