1

I have designed a view containing two labels. The title text is variable and it should look good for short and long titles, so it is set up to support multiple lines of text (numberOfLines is 0) until there is no more room available, at which point the font should shrink (adjustsFontSizeToFitWidth is true).

To demonstrate my issue I am using constant title text and adjusting the height of the container instead.

  1. Things look as expected when the height of the container is sufficient for both labels.

  1. As soon as the height isn't sufficient, instead of shrinking the title label's font, the subtitle is clipped.

  1. We prevent this via subtitleLabel.setContentCompressionResistancePriority(.required, for: .vertical). Things look better. The subtitle label is restored to the correct height and the title label's font is reduced instead.

  1. Let's reduce the height again. The subtitle label looks good still. The title label again adjusts its font, but there is a large amount of top and bottom padding. This makes some sense - there isn't enough height for three lines of title anymore, so the font size shrinks until it fits into two. But we want the label itself to reduce its height to hug the content rather than stranding the title in an ocean of space.

Expected Layout

Things I have tried:

  • Let's try to encourage it to do that using titleLabel.setContentHuggingPriority(.required, for: .vertical). No change unfortunately.
  • Let's remove that line and try something else. We've read that we should try lowering the content compression priority on the title label: titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .vertical). No change.
  • Another suggestion is to set a minimum scale factor on the title label. Let's try titleLabel.minimumScaleFactor = 0.5. No change.
  • Perhaps we should set a width constraint, even though we are already pinning to the superview? No change.
  • A few places suggest setting the label's preferredMaxLayoutWidth to match the label's width, but this also doesn't help.

Are there any other suggestions? Is there a way to accomplish this design using autolayout?

Ben Packard
  • 26,102
  • 25
  • 102
  • 183
  • You can’t have both multiline with self-adjusting height and self-adjusting font size. They are opposites. – matt Jun 26 '19 at 14:21
  • @matt I took some time isolating this issue and writing it up, any chance you could elaborate for us less competent developers? How are they opposites? Does this preclude using auto layout for such a design? If so, what are the alternatives? I'm sure many of us would appreciate it. – Ben Packard Jun 26 '19 at 14:34
  • Well, you have to do it the same way superman gets into his pants: one leg at a time. You just keep trying different sizes and measuring the string heights until you find one you like. See https://stackoverflow.com/a/33160782/341994 for the _sort_ of thing you'll have to do. – matt Jun 26 '19 at 14:59
  • Ah ok, so no autolayout (or at least a manually set height constraint based on the calculated fitting height). Might be a performance problem in a table view, no? Even with caching, etc? – Ben Packard Jun 26 '19 at 15:03
  • Are you referring to this kind of approach? https://stackoverflow.com/a/30062976/225253 (Erm don't check who asked that question, I guess I've been struggling with this for a while...) – Ben Packard Jun 26 '19 at 15:04
  • :) Well nothing has changed since you asked that version of this question. It could be argued that this makes the present version of the question a duplicate. And yes, text measurement is expensive, and a _lot_ of text measurement is _really_ expensive. – matt Jun 26 '19 at 15:18
  • Basically I'd suggest you just change your desires. The runtime is really good at letting a label grow/shrink to fit its text and letting the surrounding table view cell grow/shrink to fit the label. Why don't you just let it do what it's good at? – matt Jun 26 '19 at 15:22
  • Yep, would be awesome to always control the requirements for my projects :) – Ben Packard Jun 26 '19 at 15:25
  • 1
    Unfortunately, ROTFL is not sufficient text to constitute a valid comment on Stack Overflow. – matt Jun 26 '19 at 15:26

1 Answers1

1

The conditions for a self-sizing label (one that adjusts its height automatically to fit its contents) and a label with self-sizing text (the font size changes to fit the height) are opposites. The former assumes a fixed font size and a flexible height; the latter assumes a flexible font size and a fixed height.

You seem to be asking whether you can automagically have both at once. No, you can't. If you want a self-sizing label where the font size gets smaller once a certain amount of text is exceeded, you have to make the font size smaller.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Why are they considered opposite/mutually exclusive? Couldn't the label update its height after recalculating the font size required? I get that this *isn't* what the framework does, but you seem to be stating that id *can't* do it, as though it is a logical contradiction. Don't many views adjust their intrinsic content size based on their content? Why shouldn't a label do the same thing after a font change, even if it is one triggered by the system rather than manually? – Ben Packard Jun 26 '19 at 18:18
  • Isn't this like saying why isn't plastic conductive, or why isn't a touchdown worth 10 points? That's how the framework works. This is the game and those are the rules. The framework has certain properties built in and they work a certain way (which I've spent many years figuring out, by trial and error, what they are; and now I'm communicating that to you). If you want something else you have to write it yourself. If you have a use case for improving the framework, by all means file an enhancement request with Apple. I'm just saying what is. – matt Jun 26 '19 at 18:28
  • "You can’t have both multiline with self-adjusting height and self-adjusting font size. They are opposites." - Am I to understand you meant 'UIKit doesn't provide a way to do this' rather than 'You are requesting something that it logically impossible'? – Ben Packard Jun 26 '19 at 18:37
  • I think I've drilled down to the nub of the misunderstanding - "the latter assumes a flexible font size and a fixed height." Does it though? The label's font is adjusted to fit the *width*, not the height. This is where I am getting stuck on your insistence that there is some logical contradiction in what I am trying to accomplish. It seems reasonable to me that a label *could* 'shrink to fit' after the font calculation, i.e. update its intrinsic content size. It just doesn't. (which is fine - and you suggested an alternative). – Ben Packard Jun 26 '19 at 19:02
  • I don't insist on any logical contradiction. Logic has nothing to do with it. I'm just telling you how the feature actually works. `adjustsFontSizeToFitWidth` has no effect on a multiline label whose size is not limited as to either the number of lines or the actual height, or a label whose line break mode has `wrapping` in its name. – matt Jun 26 '19 at 19:24