31

I am struggling with maybe a bit of a rookie issue. I have a UIView within which I display some price. I want the UIView to be of a dynamic width according to the price, if its 1 Euro, then it will be e.g. 20pt, if its 2300 Euro, then it will be like 50pt in width.

I was trying to use the storyboard's constraints but without luck. Is it possible to do it within storyboard or do I have to calculate the width of UILabel and then set the width of UIView programmatically?

Thank you in advance.

rihekopo
  • 3,241
  • 4
  • 34
  • 63
kalafun
  • 3,512
  • 6
  • 35
  • 49

3 Answers3

37

Yes, you can do this in the storyboard. Add a label to your view and pin it to the left and right edge (top and bottom if you want also). Give the view constraints to its superview in the x and y directions, but do not give it a width constraint (it will need a height constraint if you didn't pin the top and bottom of the label to it). The view should then expand with the label depending on its content.

rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • Hello @rdelmar, can you please help me with this http://stackoverflow.com/questions/27103760/applying-autolayout-constraints-to-multiple-objects – Ranjit Nov 24 '14 at 12:12
  • @Ranjit, NavinDev has already answered your question, though you should not add the leading constraint as I said in my comment to his answer. – rdelmar Nov 24 '14 at 16:26
  • When you say give constraints to its superview in the x and y directions, do you mean give it any horizontal and any vertical constraint (relative to its superview)? Thanks @rdelmar! – Crashalot Dec 10 '15 at 16:42
27

In general, auto layout is performed in a top-down fashion. In other words, a parent view layout is performed first, and then any child view layouts are performed. So asking the system to size the parent based on the child is a bit like swimming upstream, harder to do, but still possible with some work.

One solution is to use the intrinsic size of a view.

For example, a UILabel has an intrinsic size based on the text in the label. If a UILabel has a leading constraint and a top constraint, but no other constraints, then its width and height are determined by its intrinsic size.

You can do the same thing with a custom view class that encloses a UILabel. By setting the intrinsic size of the custom view class based on the intrinsic size of the UILabel, you get a view that automatically resizes based on the text in the label.

Here's what the code looks like for the custom class. The .h file defines a single property text. The .m file has an IBOutlet to the child label. Setting and getting the text property simply sets or gets the text from the label. But there's one very important twist, setting the text invalidates the intrinsic size of the parent. That's what makes the system adjust the size of the parent view. In the sample code below the parent is sized to have an 8 pixel margin all around the UILabel.

SurroundView.h

@interface SurroundView : UIView
@property (strong, nonatomic) NSString *text;
@end

SurroundView.m

@interface SurroundView()
@property (weak, nonatomic) IBOutlet UILabel *childLabel;
@end

@implementation SurroundView

- (void)setText:(NSString *)text
{
    self.childLabel.text = text;
    [self invalidateIntrinsicContentSize];
}

- (NSString *)text
{
    return( self.childLabel.text );
}

- (CGSize)intrinsicContentSize
{
    CGSize size = self.childLabel.intrinsicContentSize;

    size.height += 16;
    size.width  += 16;

    return( size );
}

@end

Creating the IBOutlet to the childLabel can be a little tricky, so here's the procedure

  • drag out a UIView into the storyboard
  • use the Identity inspector to change the class to SurroundView
  • drag out a UILabel and add it as a subview of the SurroundView
  • select the label, and open the assistant editor
  • show SurroundView.m in the assistant
  • drag from the open circle to the label as shown below

enter image description here

All that's left is to get the constraints right. The constraints for the label should look like this

enter image description here

The constraints for the SurroundView should be as shown below. The key point is that the Intrinsic Size should be set to Placeholder to avoid the warnings about missing constraints.

enter image description here

user3386109
  • 34,287
  • 7
  • 49
  • 68
  • This is the key - "In general, auto layout is performed in a top-down fashion. In other words, a parent view layout is performed first, and then any child view layouts are performed." – user3344977 Jun 07 '15 at 05:28
  • 1
    I often add a width constraint, then change the constraint from = to >= and assign it a lower priority. Kudos to the answer; Intrinsic Size set to Placeholder was a revelation for me. – adamek Nov 17 '15 at 21:07
2

Place the label inside the view and pin its TOP , BOTTOM , TRAILING and LEADING edges to the labels superview. Note that you do not specify the width constraint. Now add a height and width constraint to the view. Make an outlet to the width constraint and when the price changes set the view's width constraint's constant to your desired value. Since the label is pinned to the view it will expand too.

NavinDev
  • 995
  • 1
  • 7
  • 8
  • Hello @NavinDev can you please help me with this http://stackoverflow.com/questions/27103760/applying-autolayout-constraints-to-multiple-objects – Ranjit Nov 24 '14 at 12:13