iOS: multiline uilabel only shows one line with autolayout

13,161

Solution 1

Add the line:

lbExplain.preferredMaxLayoutWidth = 280;

This must be something that is done automatically in IB, since the label expands properly if you set it up there. The number you pass it does seem to matter some in how it expands vertically, but it doesn't override the constraints you set for the width.

After Edit:

It works better if I add that line in updateViewConstraints, and relate the number to the view's bounds. This way it adjusts properly on rotation.

-(void)updateViewConstraints {
    [super updateViewConstraints];
    lbExplain.preferredMaxLayoutWidth = self.view.bounds.size.width - 40;
}

Solution 2

The issue here is that preferredMaxLayoutWidth is not set. As a result, the text is not constrained by any width and, as such, it does not wrap to the next line.

I've found that the easiest way to use a multiline UILabel with Autolayout is to create a subclass:

@interface MyMultilineLabel : UILabel

@end


@implementation MyMultilineLabel

- (void)setBounds:(CGRect)bounds {
    [super setBounds:bounds];
    CGFloat width = CGRectGetWidth(bounds);
    if (self.preferredMaxLayoutWidth != width) {
        self.preferredMaxLayoutWidth = width;
    }
}

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.lineBreakMode = NSLineBreakByWordWrapping;
        self.numberOfLines = 0;
    }
    return self;
}

@end
Share:
13,161

Related videos on Youtube

ckh
Author by

ckh

Updated on June 21, 2022

Comments

  • ckh
    ckh almost 2 years

    The code below, I think should result iin a multiline label followed by a button, however, after layout there is only a single line of the label showing up. While I could put an explicit height in the vertical layout that would defeat the purpose. Any ideas about what other constraints I should apply?

    UILabel *lbExplain = [[UILabel alloc] init];
    lbExplain.text = @"The Sync process allows you to synchronize your library between different devices. By clicking on the button below you can find other devices to sync with. The other device also has to be running this applicaton.";
    lbExplain.lineBreakMode = NSLineBreakByWordWrapping;
    lbExplain.numberOfLines = 0;
    lbExplain.translatesAutoresizingMaskIntoConstraints = NO;
    
    UIButton *btnPartner = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [btnPartner setTitle:@"Look for Partners" forState:UIControlStateNormal];
    [btnPartner addTarget:self action:@selector(findPartners:) forControlEvents:UIControlEventTouchUpInside];
    btnPartner.translatesAutoresizingMaskIntoConstraints = NO;
    
    [self.view addSubview:lbExplain];
    [self.view addSubview:btnPartner];
    
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[lbExplain]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(lbExplain)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[lbExplain]-[btnPartner]" options:NSLayoutFormatAlignAllLeft metrics:nil views:NSDictionaryOfVariableBindings(lbExplain, btnPartner)]];
    
  • rdelmar
    rdelmar about 11 years
    The OP's constraints are not ambiguous, because labels and buttons have an intrinsic height. As for your second suggestion, that's what he's trying to avoid (setting an explicit height).
  • ckh
    ckh about 11 years
    Thanks! that actually works although I'm kind of mystified as to why? 280 just seems like a magic number but it works for both the iPad and iphone (the ipad of course being way wider than 280).
  • rdelmar
    rdelmar about 11 years
    Does it really work on iPad, even if you rotate? 280 is just 320 minus the two 20 point spaces (default) to the sides that you set. I notice that on rotation on the iPhone, the label ends up with whitespace above and below the text.
  • ckh
    ckh about 11 years
    If does mostly work on the iPad. Both ipad and iphone seem to basically size the thing in what the height would be for a portrait screen so they leave extra space above and below in the wider landscape views. Not ideal, but better than the clipped text.
  • ckh
    ckh about 11 years
    Sorry missed your edit before the last response. You're right that is more consistent. Also had to add it to "didRotateFromInterfaceOrientation" in order for it to change with the orientation. It isn't exactly smooth, but functional.
  • rdelmar
    rdelmar about 11 years
    @ckh, hmm.... I don't know why you had to add it to "didRotateFromInterfaceOrientation", I didn't do that, and it adjusted perfectly to the rotation. Did you add exactly the same thing I posted?
  • ckh
    ckh about 11 years
    Replaced the implementation of updateViewConstraints with - (void)viewWillLayoutSubviews { self.explaination.preferredMaxLayoutWidth = self.view.bounds.size.width - 40; } Which worked for me, updateViewConstraints wasn't called on rotation but the layout subviews is.
  • rdelmar
    rdelmar about 11 years
    @ckh, that's strange, updateViewConstraints is called at startup and on every rotation for me.
  • Jason Moore
    Jason Moore over 7 years
    A UILabel only has an intrinsic size when it is one line.