3

I'm having trouble getting my UILabel to resize properly using Auto Layout. Basically I want my label to always be sized just big enough to match its content. Here are some pictures to demonstrate what I mean.

enter image description here

enter image description here

Notice the extra top and bottom padding in landscape orientation. I don't want that. I want the label to shrink vertically so that it just contains its content.

I have a top constraint of 33 to top layout guide, a leading constraint of 75 to superview, and a trailing constraint of 75 to superview.

So again my goal is to allow resizing of the label based on orientation, but to have the label only encompass its content without any padding.

Thanks.

myieh
  • 79
  • 1
  • 1
  • 5
  • Multi-line labels with auto-layout is tough. It looks like you need to force another layout pass when the orientation changes. Try calling `setNeedsLayout` and `layoutIfNeeded` on that view and see if that helps. This isn't an answer because knowing auto layout, this probably won't work. – larsacus Mar 03 '14 at 23:59

3 Answers3

2

What you need is a flexible constraint for the bottom of it. So let's say make the bottom constraint to be bigger than or equal to 0 and set the priority of it to 100. Then select the UILabel and change its Vertical Content Hugging priority to 99. This way the content hugging gets precedence over the bottom distance and the padding will be gone in all orientations.

P. Sami
  • 2,115
  • 2
  • 21
  • 39
2

Looks like only updating the preferredMaxLayoutWidth on any change (rotation, xib resizes etc), that effects the size, will do.

Example: I designed a view in IB with iPhone screen size like this:

iPhone Portrait

To make it work in landscape, add following code in your view controller:

- (void)updateLabelPreferredMaxLayoutWidthToCurrentWidth:(UILabel *)label
{
    label.preferredMaxLayoutWidth =[label bounds].size.width;
}

-(void)updateLabels
{
    [self updateLabelPreferredMaxLayoutWidthToCurrentWidth:self.label1];
    [self updateLabelPreferredMaxLayoutWidthToCurrentWidth:self.label2];
    [self updateLabelPreferredMaxLayoutWidthToCurrentWidth:self.label3];
}

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

    [self updateLabels];
}

Basically we are just changing the preferredMaxLayoutWidth of each label in willAnimateRotationToInterfaceOrientation, as the size is being changed there. Outcome is:

iPhone Landscape

If you want to support multiple display size, just call the updateLabels in viewDidAppear like this:

-(void)viewDidAppear:(BOOL)animated
{
    [self updateLabels];
}

This is because, I designed a single xib with iPhone display size, but want to support multiple display size. After the view is already appeared, the exact size of all the elements is calculated.

iPad Portrait Demo with same xib and adjustment code in viewDidAppear:

iPad Portrait Demo

Hope this helps.

Mesbah
  • 171
  • 7
1

Edit: here is a better answer than mine below: https://stackoverflow.com/a/15927392/3414722
It should do exactly what you want and it's fine to be used with Auto Layout.


You could call sizeToFit on the label every time the orientation is changed. In theory, sizeToFit isn't supposed to be used together with Auto Layout, but it should give you the effect you want. Here is the code you need in your view:

- (void)updateViewConstraints {
    [super updateViewConstraints];

    [self.label sizeToFit];
}

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

    [self.view setNeedsUpdateConstraints];
}
Community
  • 1
  • 1
sammalfix
  • 310
  • 4
  • 9