Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS how to make dynamic width / autolayout of UIView according to UILabel within it

Tags:

ios

autolayout

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.

like image 341
kalafun Avatar asked Jun 26 '14 18:06

kalafun


People also ask

What are two properties that auto layout constraints control on a Uiview?

Auto Layout defines margins for each view. These margins describe the preferred spacing between the edge of the view and its subviews. You can access the view's margins using either the layoutMargins or layoutMarginsGuide property. The layoutMargins property lets you get and set the margins as a UIEdgeInsets structure.

How does a view's intrinsic content size aid in auto layout?

In general, the intrinsic content size simplifies the layout, reducing the number of constraints you need. However, using the intrinsic content size often requires setting the view's content-hugging and compression-resistance (CHCR) priorities, which can add additional complications.

What is intrinsic content size?

Intrinsic content size is information that a view has about how big it should be based on what it displays. For example, a label's intrinsic content size is based on how much text it is displaying. In your case, the image view's intrinsic content size is the size of the image that you selected.

What is translatesAutoresizingMaskIntoConstraints?

translatesAutoresizingMaskIntoConstraints. A Boolean value that determines whether the view's autoresizing mask is translated into Auto Layout constraints.


2 Answers

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.

like image 170
rdelmar Avatar answered Oct 22 '22 10:10

rdelmar


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

like image 27
user3386109 Avatar answered Oct 22 '22 11:10

user3386109