18

Why exactly is preferredMaxLayoutWidth needed?

UIKit reference says

preferredMaxLayoutWidth

The preferred maximum width (in points) for a multiline label.

This property affects the size of the label when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text is flowed to one or more new lines, thereby increasing the height of the label.

Notice this:

if the text extends beyond the width specified by this property, the additional text is flowed to one or more new lines

So, on a multiline label, if the preferredMaxLayoutWidth property wasn't set, would the text just go on beyond the bounds of the UILabel? Why would would we ever want that to happen on a label we explicitly set to be multiline?

What is really the reason this property exists? Is it something with Auto Layout? Please explain, i really want to understand this.

quad16
  • 184
  • 5
  • 20
  • A very goo use case would be limit the a UILabel's width the a tableView's bounds. Example you'll do `cell.myCellLabel.preferredMaxLayoutWidth = tableView.bounds.width`. For more see [here](https://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights/52673314#52673314). A – mfaani Oct 05 '18 at 22:13

1 Answers1

22

Your guess is right on – it has to do with Auto Layout. When the system needs to lay out a multiline label, it needs to know two dimensions: the width and the height of the label.

Sometimes, you constrain one or both explicitly: you can say "I want my label to be 300 points wide," or "I want my label exactly one line tall." The system can then figure out the other dimension based on your constraint and the text in the label.

Other times, though, you don't constrain either – you might want the label to wrap within available space, but shrink horizontally if it doesn't have a lot of text in it, so you don't constrain either the width or the height exactly. In that case, Auto Layout can get confused, because text doesn't really have an "intrinsic size" the way a lot of other content does. For example:

A sentence can be quite long horizontally,

or
it
might
be
skinny
but
tall

Both of those layouts – and many in between – would be equally valid in Auto Layout's eyes. To help guide it, Apple introduced the preferredMaxLayoutWidth property for wrapping labels. If your label doesn't explicitly set an exact width or height, UIKit will start laying out text on the first line until you hit the preferred maximum width for that layout, then wrap and continue the process on each subsequent line.

If preferredMaxLayoutWidth isn't set, the text won't extend beyond the bounds of the label. Instead, one of two things would happen:

  • The label would get wider and wider, expanding its frame.size.width to fit the text on one line until it was all rendered, or
  • The label would truncate its text

Effectively, this makes the preferredMaxLayoutWidth property a mechanism for guiding Auto Layout's behavior when wrapping text without requiring you to write a bunch of dynamic constraints code to achieve the same effect. It's quite a handy shortcut, especially when combined with some of the Interface Builder options to set the max layout width to e.g. the First Runtime Layout Width or Automatic.

Hope that helps clear things up!

Tim
  • 59,527
  • 19
  • 156
  • 165
  • Thank you very much for this answer. I've been struggling with understanding Auto Layout and things related to it, and your explanation is very clear and pleasant to read. I wish all of Apples documentation was like this. I've upvoted your answer and i'd just like you to comment one thing before i accept you answer. Does preferredMaxLayoutWidth do anything more, or less, or different, than just setting a simple width constraint does? Is that wholly and completely what it is, a shortcut to create a width constraint? – quad16 Jul 20 '16 at 17:04
  • Oh! Maybe it's this: before constraints were added in Interface Builder, preferredMaxLayoutWidth was needed to specify the width of a multiline label (because accepting the bounds width was not considered enough? wait...) edit: no this can't be it because this thing didn't exist before constraints did, UIKit reference states preferredMaxLayoutWidth was added in iOS 6.0. Hmm... Well maybe it really is just a shortcut for creating a width constraint? – quad16 Jul 20 '16 at 17:08
  • 1
    What is First Runtime Layout Width? – quad16 Jul 20 '16 at 17:17
  • 3
    `preferredMaxLayoutWidth` is *less constraining* than adding an exact width constraint. It adds the flexibility of letting wrapping labels shrink horizontally if there's less than a line of text in them, and it may also wrap words just short of the width if your text doesn't completely fill a line of that width. It's not a constraint; it's just an Auto Layout helper to simplify your constraint system. – Tim Jul 20 '16 at 17:33
  • First Runtime Layout Width is an IB setting that lays out all your views once, then automatically sets the label's `preferredMaxLayoutWidth` to the computed width of the label after that first layout. From that point forward, Auto Layout will use that width in future layout passes. It's convenient for automatically adjusting the max layout width based on how a view appears in IB. – Tim Jul 20 '16 at 17:34
  • 1
    Hey Tim. After a lot of investigating I've came to conclusion, that if we want automatically 'preferredMaxLayoutWidth' based on the view size (I.E setting Width constraint same as super view). We can't do it solo from IB, and we have to combine code. Am I right? + Can you explain more about what to use ' First Runtime Layout Width' in practice? – Roi Mulia Jul 18 '17 at 12:06
  • @Tim Forgot to tag you, please see comment above – Roi Mulia Jul 18 '17 at 12:06
  • @RoiMulia I don't think you need code. You can set up leading and trailing constraints from your label to its superview (effectively keeping its width the same as that superview), then choose First Runtime Layout Width in IB. Then, at runtime, your view will get a width; the label will lay out at the same width, because of the leading+trailing constraints; and the text will wrap within that width, because of the First Runtime Layout Width setting. (If you need more details, please consider asking a new question instead of commenting here further.) – Tim Jul 19 '17 at 16:46
  • 1
    Hey @Tim, Thank you so much for responding! I don't need anymore details :) Tho excuse me for my ignorance, But I literally searched for 30 min over the IB Inspector tab, on xCode 8, on UILabel object, and couldn't find this property. Am I missing something? – Roi Mulia Jul 19 '17 at 17:31
  • 1
    I think in Xcode 8, they shortened the name to "Preferred Width" and will use First Layout Runtime Width automatically unless you set an explicit value. With a UILabel selected, it's in the fifth tab in the right sidebar (the Size inspector) – it appears as a text box with placeholder text "Automatic" and a checkbox labeled "Explicit" next to it. Leaving it Automatic *should* get you First Layout Runtime Width behavior. – Tim Jul 21 '17 at 15:39
  • 1
    Hey @Tim.Thank you for the detailed answer. After tons of trying & investigate, It does not seems to work (Maybe I haven't understood how to use it). Meaning, It will not expect the "dynamic width" the applied constraint (For example, same Width as Superview). It's working only when using the "explicit" value, setting him to a constant. Maybe It won't work for Equal Width, but will work for "pin to superview edges"? Anyway, I've made an UILabel Extension, overriding "layoutSubiews", and just make the "Preferred Width" same as UILabel frame width As automatic as I could. Haha. Hope i'm wrong – Roi Mulia Jul 22 '17 at 23:01
  • This still confuses me, why go through the hassle of setting another property when I can just set the width as a regular width-contraint and the numberOfLines to 0? In which case would this property help me better? – Kevin R Apr 18 '19 at 07:05
  • I answer this in my post: "you might want the label to wrap within available space, but shrink horizontally if it doesn't have a lot of text in it, so you don't constrain either the width or the height exactly." If you use "a regular width-constraint," you risk an inflexible or incorrect layout, which can cause problems on varying iOS device sizes. – Tim Apr 19 '19 at 22:15
  • It's also worth noting that in more recent versions of iOS, "automatic" width is available, which generally means you don't need to manage this property yourself. (Even back then, using First Layout Runtime Width was an effective shortcut to solving this problem without needing to put in a ton of work.) – Tim Apr 19 '19 at 22:16
  • This property still makes no sense to me. You could get the same effect setting a maximum width constraint on a label (constraints can also be <= and >=, not just ==). The label would then grow until it cannot grow any further without violating that constraints and then it would either clip, truncate, or wrap, depending on what you've configured at "Layout". With min/max constraints in place, why would you need such a property? – Mecki May 28 '19 at 15:57
  • @Mecki This property is very useful in cases where the label doesn't have constraints set. I'm working on a project where this has fixed layout issues for me. – Leon Oct 14 '20 at 09:26