Dynamic UILabel with proportional width and text-driven height

11,112

To make your labels automatically resize height you need to do following:

  1. Set layout constrains for label (That what you actually have done)
  2. Set height constraint with low priority. It should be lover than ContentCompressionResistancePriority
  3. Set numberOfLines = 0
  4. Set ContentHuggingPriority higher than label's hight priority
  5. Set preferredMaxLayoutWidth for label. That value is used by label to calculate its height

For example:

self.descriptionLabel = [[[UILabel alloc] init] autorelease];
self.descriptionLabel.numberOfLines = 0;
self.descriptionLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.descriptionLabel.preferredMaxLayoutWidth = 200;

[self.descriptionLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.descriptionLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:self.descriptionLabel];

NSArray* constrs = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[descriptionLabel_]-8-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)];
[self addConstraints:constrs];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[descriptionLabel_]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
[self.descriptionLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[descriptionLabel_(220@300)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel_)]];
Share:
11,112
lencharest
Author by

lencharest

Updated on June 20, 2022

Comments

  • lencharest
    lencharest almost 2 years

    I'm trying to programmatically create a container view with two UILabel subviews which behave as follows:

    • The container width is pinned to its superview; its height is constrained to fit the labels
    • The labels are laid out horizontally, with standard spacing between them (8pts)
    • The left label width is 25% of the width of the container
    • The right label width fills the available space, minus standard horizontal spacing
    • Long text should be broken at word boundaries are flow across multiple lines; both labels must grow vertically to accommodate long text

    I have defined the labels with numberOfLines = 0 and lineBreakMode = NSLineBreakByWordWrapping.

    Note that the size of the container is completely dynamic; its width is determined by its superview, while its height is determined by its subviews (the labels). The size of the labels is also dynamic; their widths are proportional to the container width, and their heights depend on the length of the text.

    I've been able to achieve everything above, except for the last item, with the following constraints (pseudo-code). A is the left label, B is the right.

    • A.top == container.top
    • B.top == container.top
    • A.leading = container.leading
    • A.trailing == B.leading - 8
    • B.trailing == container.trailing
    • A == .25 * container.width
    • container.height >= A.height
    • container.height >= B.height

    The last 2 constraints are intended to stretch the container to fit the taller of the labels, but the layout engine seems to ignore the fact that the labels may be multiline. That is, I always get a single line displayed, no matter the length of the text.

    So what constraints do I need to add/modify/delete in order to achieve the full set of behaviors described above?