XJones
XJones

Reputation: 21967

How do I define a layout constraint to keep one label the width of its content and allow another label to fill the remaining space?

Consider the following desired layout. Note that this is not a "layout string" but a proxy for a picture. So | = superview edges, - = space, [xxx] = a view.

|--[label1]--[label2--------------]--[button]--|

The above layout is what I'm trying to achieve. In english:

I hope this is clear. My current constraint is defined as:

[NSLayoutConstraint
 constraintsWithVisualFormat:@"H:|-8-[label1]-4-[label2]-4-[button]-8-|"
 options:0
 metrics:nil
 views:views];

This results in the following layout:

|--[label1----------------------]--[label2]--[button]--|

Question: how can I modify the constraint so label2 is proportionally sized and label and button are sized to fit content?

-- EDIT --

If it helps, here is equivalent code to create the constraints generated by the above sample.

NSLayoutConstraint *c1 = [NSLayoutConstraint
                          constraintWithItem:self.label1
                          attribute:NSLayoutAttributeLeading
                          relatedBy:NSLayoutRelationEqual
                          toItem:self
                          attribute:NSLayoutAttributeLeading
                          multiplier:1.0f
                          constant:8.0f];

NSLayoutConstraint *c2 = [NSLayoutConstraint
                          constraintWithItem:self.label2
                          attribute:NSLayoutAttributeLeading
                          relatedBy:NSLayoutRelationEqual
                          toItem:self.label1
                          attribute:NSLayoutAttributeTrailing
                          multiplier:1.0f
                          constant:4.0f];

NSLayoutConstraint *c3 = [NSLayoutConstraint
                          constraintWithItem:self.button
                          attribute:NSLayoutAttributeLeading
                          relatedBy:NSLayoutRelationEqual
                          toItem:self.label2
                          attribute:NSLayoutAttributeTrailing
                          multiplier:1.0f
                          constant:4.0f];

NSLayoutConstraint *c4 = [NSLayoutConstraint
                          constraintWithItem:self
                          attribute:NSLayoutAttributeTrailing
                          relatedBy:NSLayoutRelationEqual
                          toItem:self.button
                          attribute:NSLayoutAttributeTrailing
                          multiplier:1.0f
                          constant:8.0f];

Upvotes: 1

Views: 3878

Answers (2)

XJones
XJones

Reputation: 21967

@ilya's answer is a partial solution. It does keep label1 from expanding but label2 can still extend into the area I wanted button to be in and `button can be compressed. After some trial and error and reading all the docs, I've found a better, and more appropriate solution. Been fun learing auto layout.

Rather than specifying a minimum width for label1, which is somewhat artificial and also leaves other problems depending on view content, a better solution is to set the contentCompressionResistancePriority and the contentHuggingPriority for all views.

The constraints as shown in my question work perfectly as long as I also add the following:

    [self.label1
     setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh
     forAxis:UILayoutConstraintAxisHorizontal];
    [self.label1
     setContentHuggingPriority:UILayoutPriorityDefaultLow
     forAxis:UILayoutConstraintAxisHorizontal];
    [self.label2
     setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
     forAxis:UILayoutConstraintAxisHorizontal];
    [self.label2
     setContentHuggingPriority:UILayoutPriorityDefaultHigh
     forAxis:UILayoutConstraintAxisHorizontal];
    [self.button
     setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh
     forAxis:UILayoutConstraintAxisHorizontal];
    [self.button
     setContentHuggingPriority:UILayoutPriorityDefaultLow
     forAxis:UILayoutConstraintAxisHorizontal];

Upvotes: 5

ilya n.
ilya n.

Reputation: 18816

Just add another constraint for width of label1 to equal some minimum size (e.g. in the interface builder when you add width constraint it will use current width automatically) but set its priority to be lower.

Upvotes: 1

Related Questions