3
votes

If I throw together scenes consisting of either of the following two view hierarchies and constraints (easily done in InterfaceBuilder), then everything works as expected...


1)

  • A full-screen UIScrollView (0 distance to all edges of the superview)
  • Within the UIScrollView, a single UILabel, with numberOfLines set to 0, with 100% width (0 distance leading and trailing constraints), with no height constraint, with enormous amounts of text (1000s of lines), and with top and bottom constraints with a constant of 0 (so that there should be 0 distance from the boundaries of the UILabel to the content view of the UIScrollView).

Behaviour is as expected: the UILabel gets sized to fit its contents, which forces the content view of the UIScrollView to expand to fit the text, making all the text scrollable.


2)

  • A UILabel with numberOfLines equal to 0 within some UIView innerView within some UIView outerView such that:
    • The label's edges all have 0 distance from innerView's edges (with priority 1000)
    • innerView's edges all have 0 distance from outerView's edges (with priority 1000)
    • outerView's top, leading and trailing edges all have 0 distance from the superview (with priority 1000)
    • outerView has a height that is less than the full height of its superview, enforced either by a height constraint or a bottom-distance-to-superview constraint, but this final constraint has some lower priority - say, 600.

In this case the behaviour is again as expected: if the UILabel's Content Compression Resistance Priority is greater than 600, outerView's height gets increased to fit all the text, and if it's less, the label gets truncated.


However the following case does not work the way I would expect, despite appearing to me to be exactly analogous to the other two:

3)

  • A full-screen UIScrollView, like the first case
  • Within the UIScrollView, a UIView innerView whose edges all have 0 distance from the UIScrollView's edges (like the second case).
  • Within innerView, a UILabel with numberOfLines set to 0, loads of text, and Content Compression Resistance Priority set to 1000.

My expectation, based upon the previous two test cases, is that the UIScrollView's content view should resize to fit the text of the label. However, instead what happens is that the content view gets set to the size of the UIScrollView, as does innerView, and the UIScrollView is not scrollable.

Why am I getting this behaviour which is inconsistent with my previous two test cases, and how can I get working content compression resistance and have the intrinsic content size of my UILabel respected when I'm nesting it in a view within a UIScrollView under autolayout? I can't see any reason for autolayout to compress my UILabel in the third case when it is perfectly possible for it to not compress it and still satisfy all constraints in exactly the same way as it did in the first case.

1

1 Answers

2
votes

I had the same issue. There seems to be a bug with apple, so multiline text requires a two-pass approach to layout correct and it all relies on the property preferredMaxLayoutWidth.

I ended up adding these two methods to the ScrollViewController:

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self performSelectorOnMainThread:@selector(adjustScrollContentSizeOnMainThread) withObject:nil    waitUntilDone:NO];
}

- (void)adjustScrollContentSizeOnMainThread
{
    self.myLabel.preferredMaxLayoutWidth = self.myLabel.bounds.size.width;
}

I based my solution on this answer: https://stackoverflow.com/a/13616052/2828256