newDeveloper newDeveloper - 1 year ago 133
iOS Question

Autolayout adding extra padding on top and bottom of UILabel iPhone 6/6+ when preferredMaxLayoutWidth is set

I created a sample project to reproduce this.

I've a xib file with an UILabel having a fixed top, leading and trailing constraint. I added a minHeight constraint and set the number of lines to 0.

I set the preferredMaxLayoutWidth to Automatic (checked in the xib file).

In viewDidLoad, I've this:

self.myLabel.layer.borderColor = [[UIColor redColor] CGColor];
self.myLabel.layer.borderWidth = 2.0f;

self.myLabel.text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

And when i run the simulator on iPhone 6 or 6+, I get this:

enter image description here

I've no idea where that top and bottom padding is coming from and it's proportional to the amount of characters in the UILabel is showing.

Is there some magic setting I forgot ? It runs fine on iPhone 4" devices.

Now if I don't set the preferredMaxLayoutWidth, it doesn't have the extra padding but this breaks my multi-lines in the UILabel. It cuts off the text. I did not use Size-Class.


So I changed few things on my sample project to match the situation on my real project. I've added a tableView (with top, leading, bottom and trailing constraints set to its parent view). Each cell on the tableView has 4 labels. The top label has a top, leading and trailing constraint to the contentView of the cell and the subsequent labels have a vertical constraint to the label above it. Every label has a heightGreaterThan constraint set and a widthGreaterThan set.

This is how it looks like without the preferredMaxLayoutWidth set (Notice how labels are capped to 1 line).
No preferredMaxLayoutWidth

With preferredMaxLayoutWidth. Now the UILabel shows the entire content but has a padding on top and bottom.
With preferredMaxLayoutWidth but with top and bottom padding

Sample Project:

Answer Source

So what i ended up doing was to create a subclass for the label and override setBounds: and set the preferredMaxLayoutWidth to its bounds.

- (void)setBounds:(CGRect)bounds {
    [super setBounds:bounds];

    if (self.preferredMaxLayoutWidth != bounds.size.width) {
        self.preferredMaxLayoutWidth = bounds.size.width;
        [self setNeedsUpdateConstraints];

Also, in the UITableViewCell subclass, i override the layoutSubiews

- (void)layoutSubviews {
    [super layoutSubviews];

    [self.contentView layoutIfNeeded];

    // labelsCollection is an IBOutletCollection of my UILabel sublasses
    for (UILabel *label in self.labelsCollection) {
        label.preferredMaxLayoutWidth = label.bounds.size.width;

This works all the time. I think the reason for this odd behavior is that the UILabel is initially set to 280px (320px - padding on either side) in the xib file but during run time, it changes its width to accommodate bigger screens (since I set the leading and trailing constraints it increases the width which changes the 'preferredMaxLayoutWidth' to a bigger value). For some reason UILabel doesn't update its preferredMaxLayoutWidth to the bigger value and causes the white space on top and bottom.

That's my hypothesis.

Hope this helps.