iOS Autolayout: Issue with UILabels in a resizing parent view

autolayout, ios, ios6

Solution

I've fixed this issue after raising a bug with Apple. The issue that multiline text requires a two-pass approach to layout and it all relies on the property `preferredMaxLayoutWidth`

Here is the relevant code that needs to be added to a view controller that contains a multiline label:

- (void)viewWillLayoutSubviews
{
    // Clear the preferred max layout width in case the text of the label is a single line taking less width than what would be taken from the constraints of the left and right edges to the label's superview
    [self.label setPreferredMaxLayoutWidth:0.];
}

- (void)viewDidLayoutSubviews
{
    // Now that you know what the constraints gave you for the label's width, use that for the preferredMaxLayoutWidth—so you get the correct height for the layout
    [self.label setPreferredMaxLayoutWidth:[self.label bounds].size.width];

    // And then layout again with the label's correct height.
    [self.view layoutSubviews];
}

Problem

I've got a view that contains only a UILabel. This label contains multiline text. The parent has a variable width that can be resized with a pan gesture. My problem is that when I do this resizing the UILabel does not recalculate its height such that all of the content is still visible, it simply cuts it off. I've managed to fix it with a bit of a hack but it is horribly slow to run: ``` - (void)layoutSubviews { CGSize labelSize = [self.labelDescription sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)]; if (self.constraintHeight) { [self removeConstraint:self.constraintHeight]; } self.constraintHeight = [NSLayoutConstraint constraintWithItem:self.labelDescription attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:labelSize.height]; [self addConstraint:self.constraintHeight]; [super layoutSubviews]; } ``` Shouldn't this happen automatically with autolayout? EDIT The structure of my view is: ``` UIScrollView ---> UIView ---> UILabel ``` Here are the constraints on the UIScrollView: ``` <NSLayoutConstraint:0x120c4860 H:|-(>=32)-[DescriptionView:0x85c81c0] (Names: '|':UIScrollView:0x85db650 )>, <NSLayoutConstraint:0x120c48a0 H:|-(32@900)-[DescriptionView:0x85c81c0] priority:900 (Names: '|':UIScrollView:0x85db650 )>, <NSLayoutConstraint:0x120c48e0 H:[DescriptionView:0x85c81c0(<=576)]>, <NSLayoutConstraint:0x120c4920 H:[DescriptionView:0x85c81c0]-(>=32)-| (Names: '|':UIScrollView:0x85db650 )>, <NSLayoutConstraint:0x120c4960 H:[DescriptionView:0x85c81c0]-(32@900)-| priority:900 (Names: '|':UIScrollView:0x85db650 )>, <NSLayoutConstraint:0x8301450 DescriptionView:0x85c81c0.centerX == UIScrollView:0x85db650.centerX>, ``` Here are the constraints on the UIView: ``` <NSLayoutConstraint:0x85c4580 V:|-(0)-[UILabel:0x85bc7b0] (Names: '|':DescriptionView:0x85c81c0 )>, <NSLayoutConstraint:0x85c45c0 H:|-(0)-[UILabel:0x85bc7b0] (Names: '|':DescriptionView:0x85c81c0 )>, <NSLayoutConstraint:0x85c9f80 UILabel:0x85bc7b0.trailing == DescriptionView:0x85c81c0.trailing>, <NSLayoutConstraint:0x85c9fc0 UILabel:0x85bc7b0.centerY == DescriptionView:0x85c81c0.centerY> ``` The UILabel itself has no constraints on it, aside from pinning it to the edges of its parent

Original source