Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImageView with auto-layout and max size keeping aspect ratio

I have a UIImageView generated in source (programmatically). That UIImageView needs to have a max size, for both width and height. In this view, I load a image from URL and set after the download ends. I don't know previously, what is the size of the image, but I need to keep the aspect ratio and make the UIImageView with a size that maintains that aspect.

If the image is smaller, in one or both dimension, I want the UIImageView has the size necessary to maintain the aspect ratio without stretch the image.

I'll give two examples considering the max size for UIImageView with 250 X 350.

Example 1:

The image size is 800 X 800. The size of UIImageView needs to be 250 X 250.

Example 2:

The image size is 200 X 250. The size of UIImageView needs to be 200 X 250.

How can I do this with auto-layout.

like image 362
Mário Klein Avatar asked Mar 26 '15 20:03

Mário Klein


1 Answers

You'll need three constraints here. One that maintains the aspect ratio, one that makes sure the width is no larger than the maximum, and one that makes sure the height is no larger than the maximum. As of August 2016, Interface Builder does not support constraints referencing other constraints, so – at a minimum – the aspect ratio constraint must be done in code.

The aspect ratio is the only one that takes any thinking. Let V_w and V_h be the width and height, respectively, of your image view. Let I_w and I_h be the width and height, respectively, of your image. Then, to maintain the image's aspect ratio, the following equation must remain true:

V_w / V_h = I_w / I_h

Or, equivalently:

V_w = (I_w / I_h) * V_h

Ok, looking good. Let's write some code. In this code, I assume you have MAX_HEIGHT and MAX_WIDTH defined earlier. Note that this code must target iOS 9.0 or later. If you're targeting an earlier version of iOS, see the block below.

// Constrain the desired aspect ratio
[imageView.widthAnchor constraintEqualToAnchor:imageView.heightAnchor
                                    multiplier:aspectRatioMult].active = YES;

// Constrain height
[imageView.heightAnchor constraintLessThanOrEqualToConstant:MAX_HEIGHT].active = YES;

// Constrain width
[imageView.widthAnchor constraintLessThanOrEqualToConstant:MAX_WIDTH].active = YES;

For code targeting iOS versions before 9.0, NSLayoutAnchor is not available. Instead, you'll have to make due with NSLayoutConstraint.

CGFloat aspectRatioMult = (imageView.image.size.width / imageView.image.size.height);

// Constrain the desired aspect ratio
[imageView addConstraint:
  [NSLayoutConstraint constraintWithItem:imageView
                               attribute:NSLayoutAttributeWidth
                               relatedBy:NSLayoutRelationEqual
                                  toItem:imageView
                               attribute:NSLayoutAttributeHeight
                              multiplier:aspectRatioMult
                                constant:0]];

// Constrain height
[imageView addConstraints:
  [NSLayoutConstraint constraintsWithVisualFormat:@"V:[imageView(<=max)]"
                                          options:0
                                          metrics:@{@"max" : @(MAX_HEIGHT)}
                                            views:@{@"imageView" : imageView}]];

// Constrain width
[imageView addConstraints:
  [NSLayoutConstraint constraintsWithVisualFormat:@"H:[imageView(<=max)]"
                                          options:0
                                          metrics:@{@"max" : @(MAX_WIDTH)}
                                            views:@{@"imageView" : imageView}]];
like image 155
ravron Avatar answered Sep 22 '22 17:09

ravron