Align UIImageView with Aspect Fit

for my UIImageView I choose Aspect Fit (InterfaceBuilder), but how do I change the vertical alignment?

+69
iphone cocoa-touch interface-builder
Jul 17 2018-10-17T00:
source share
11 answers

[EDIT - this code is a bit moldy since 2011, and all but the built-in @ArtOfWarefare mods]

You cannot do this with UIImageView. I created a simple subclass of UIView MyImageView containing a UIImageView. The code is below.

 // MyImageView.h #import <UIKit/UIKit.h> @interface MyImageView : UIView { UIImageView *_imageView; } @property (nonatomic, assign) UIImage *image; @end 

and

 // MyImageView.m #import "MyImageView.h" @implementation MyImageView @dynamic image; - (id)initWithCoder:(NSCoder*)coder { self = [super initWithCoder:coder]; if (self) { self.clipsToBounds = YES; _imageView = [[UIImageView alloc] initWithFrame:self.bounds]; _imageView.contentMode = UIViewContentModeScaleAspectFill; [self addSubview:_imageView]; } return self; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.clipsToBounds = YES; _imageView = [[UIImageView alloc] initWithFrame:self.bounds]; _imageView.contentMode = UIViewContentModeScaleAspectFill; [self addSubview:_imageView]; } return self; } - (id)initWithImage:(UIImage *)anImage { self = [self initWithFrame:CGRectZero]; if (self) { _imageView.image = anImage; [_imageView sizeToFit]; // initialize frame to be same size as imageView self.frame = _imageView.bounds; } return self; } // Delete this function if you're using ARC - (void)dealloc { [_imageView release]; [super dealloc]; } - (UIImage *)image { return _imageView.image; } - (void)setImage:(UIImage *)anImage { _imageView.image = anImage; [self setNeedsLayout]; } - (void)layoutSubviews { if (!self.image) return; // compute scale factor for imageView CGFloat widthScaleFactor = CGRectGetWidth(self.bounds) / self.image.size.width; CGFloat heightScaleFactor = CGRectGetHeight(self.bounds) / self.image.size.height; CGFloat imageViewXOrigin = 0; CGFloat imageViewYOrigin = 0; CGFloat imageViewWidth; CGFloat imageViewHeight; // if image is narrow and tall, scale to width and align vertically to the top if (widthScaleFactor > heightScaleFactor) { imageViewWidth = self.image.size.width * widthScaleFactor; imageViewHeight = self.image.size.height * widthScaleFactor; } // else if image is wide and short, scale to height and align horizontally centered else { imageViewWidth = self.image.size.width * heightScaleFactor; imageViewHeight = self.image.size.height * heightScaleFactor; imageViewXOrigin = - (imageViewWidth - CGRectGetWidth(self.bounds))/2; } _imageView.frame = CGRectMake(imageViewXOrigin, imageViewYOrigin, imageViewWidth, imageViewHeight); } - (void)setFrame:(CGRect)frame { [super setFrame:frame]; [self setNeedsLayout]; } @end 
+40
Apr 04 2018-11-11T00:
source share

When using storyboards, this can be achieved using restrictions ...

Firstly, a UIView with the required final frame / constraint. Add a UIImageView to the UIView. Set the contentMode parameter to Aspect Fill. Make the UIImageView frame equal to the ratio of the image (this avoids any warnings about the storyboard later). Connect the sides to the UIView using standard constraints. Attach the top OR bottom (depending on where you want to align it) with the UIView using standard restrictions. Finally, add an aspect ratio constraint to the UIImageView (image quality assurance ratio).

+29
Dec 19 '14 at 15:38
source share

This is a bit more complicated, since there is no way to set additional alignment rules if you have already selected the content mode ( .scaleAspectFit ).

But here is a workaround to this:

First, you must explicitly resize the original image by calculating the dimensions (if it were in a UIImageView with contentMode =.scaleAspectFit ).

 extension UIImage { func aspectFitImage(inRect rect: CGRect) -> UIImage? { let width = self.size.width let height = self.size.height let aspectWidth = rect.width / width let aspectHeight = rect.height / height let scaleFactor = aspectWidth > aspectHeight ? rect.size.height / height : rect.size.width / width UIGraphicsBeginImageContextWithOptions(CGSize(width: width * scaleFactor, height: height * scaleFactor), false, 0.0) self.draw(in: CGRect(x: 0.0, y: 0.0, width: width * scaleFactor, height: height * scaleFactor)) defer { UIGraphicsEndImageContext() } return UIGraphicsGetImageFromCurrentImageContext() } } 

Then you just need to call this function on the original image by passing the imageView and UIImageView.image frame to the UIImageView.image property. Also make sure you set your imageView to the desired contentMode here (or even in the Interface contentMode )!

 let image = UIImage(named: "MySourceImage") imageView.image = image?.aspectFitImage(inRect: imageView.frame) imageView.contentMode = .left 
+9
Aug 21 '17 at 9:42 on
source share

Try to install:

 imageView.contentMode = UIViewContentModeScaleAspectFit; imageView.clipsToBounds = YES; 

It worked for me.

+8
Jan 30 '13 at
source share

I used UIImageViewAligned to change image alignment thanks to the developer

UIImageViewAligned

+3
Feb 22 '16 at 13:17
source share

I know this is an old thread, but I thought I would share what I did to easily change the cropped region from top to bottom in the image view in Interface Builder, if someone had the same problem as me, I there was a UIImageView that populated the view of my ViewController and tried to make the top stop the same regardless of the screen size of the device.

  • I applied the retina 4 form factor (Editor-> Apply Retina 4 Form Factor).

  • I pinned the height and width.

Now that the screen is resized, the UIImageView is actually the same size, and the view controller simply pinches what is disconnected from the screen. The beginning of the frame remains at 0.0, so the bottom and right of the image are cropped, not the top.

Hope this helps.

+2
Jun 13 '13 at 0:10
source share

You can do this by first scaling and then resizing. The fact is that I was due to growth. I mean, I had to have an image 34 pixels high and regardless of width.

So, get the ratio between the actual content height and presentation height (34 px), and then scale the width as well.

Here is how I did it:

 CGSize size = [imageView sizeThatFits:imageView.frame.size]; CGSize actualSize; actualSize.height = imageView.frame.size.height; actualSize.width = size.width / (1.0 * (size.height / imageView.frame.size.height)); CGRect frame = imageView.frame; frame.size = actualSize; [imageView setFrame:frame]; 

Hope this helps.

+1
02 Oct
source share

I came to the following solution:

  1. Set UIImageView contents of UIImageView top : imageView.contentMode =.top
  2. Resize image to fit UIImageView borders

To download and resize the image, I use Kingfisher :

 let size = imageView.bounds.size let processor = ResizingImageProcessor(referenceSize: size, mode: .aspectFit) imageView.kf.setImage(with: URL(string: imageUrl), options: [.processor(processor)]) 
+1
Mar 04 '19 at 18:08
source share

I solved this by subclassing the UIImageView and overriding the setImage: method. The subclass will first save the original values ​​for the start and size so that it can use the original size of the set as a bounding box.

I set the content mode to UIViewContentModeAspectFit. Inside setImage: I grabbed the ratio of image width to height, and then resized the image to fit the same ratio as the image. After resizing, I adjusted the frame properties to set the image in the same place as before, and then I called super setImage :.

This leads to the presentation of the image, the frame of which is adjusted to exactly match the image, so the aspect is suitable and the properties of the image frame make heavy lifting when placing the image where it should be in order to get the same effect.

Here is the code I used:

First of all, and I believe that this is quite useful in general, this is a category in UIView that simplifies setting frame properties when viewing using properties such as left, right, top, bottom, width, height, etc.

UIImageView + FrameAdditions

 @interface UIView (FrameAdditions) @property CGFloat left, right, top, bottom, width, height; @property CGPoint origin; @end @implementation UIView (FrameAdditions) - (CGFloat)left { return self.frame.origin.x; } - (void)setLeft:(CGFloat)left { self.frame = CGRectMake(left, self.frame.origin.y, self.frame.size.width, self.frame.size.height); } - (CGFloat)right { return self.frame.origin.x + self.frame.size.width; } - (void)setRight:(CGFloat)right { self.frame = CGRectMake(right - self.frame.size.width, self.frame.origin.y, self.frame.size.width, self.frame.size.height); } - (CGFloat)top { return self.frame.origin.y; } - (void)setTop:(CGFloat)top { self.frame = CGRectMake(self.frame.origin.x, top, self.frame.size.width, self.frame.size.height); } - (CGFloat)bottom { return self.frame.origin.y + self.frame.size.height; } - (void)setBottom:(CGFloat)bottom { self.frame = CGRectMake(self.frame.origin.x, bottom - self.frame.size.height, self.frame.size.width, self.frame.size.height); } - (CGFloat)width { return self.frame.size.width; } - (void)setWidth:(CGFloat)width { self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, width, self.frame.size.height); } - (CGFloat)height { return self.frame.size.height; } - (void)setHeight:(CGFloat)height { self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, height); } - (CGPoint)origin { return self.frame.origin; } - (void)setOrigin:(CGPoint)origin { self.frame = CGRectMake(origin.x, origin.y, self.frame.size.width, self.frame.size.height); } @end 

This is a subclass of UIImageView. It is not fully tested, but should get this idea. This can be expanded to customize your own new alignment modes.

BottomCenteredImageView

 @interface BottomCenteredImageView : UIImageView @end @interface BottomCenteredImageView() { CGFloat originalLeft; CGFloat originalBottom; CGFloat originalHeight; CGFloat originalWidth; } @end @implementation BottomCenteredImageView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if(self) { [self initialize]; } return self; } - (void)awakeFromNib { [self initialize]; } - (void)initialize { originalLeft = self.frame.origin.x; originalHeight = CGRectGetHeight(self.frame); originalWidth = CGRectGetWidth(self.frame); originalBottom = self.frame.origin.y + originalHeight; } - (void)setImage:(UIImage *)image { if(image) { self.width = originalWidth; self.height = originalHeight; self.left = originalLeft; self.bottom = originalBottom; float myWidthToHeightRatio = originalWidth/originalHeight; float imageWidthToHeightRatio = image.size.width/image.size.height; if(myWidthToHeightRatio >= imageWidthToHeightRatio) { // Calculate my new width CGFloat newWidth = self.height * imageWidthToHeightRatio; self.width = newWidth; self.left = originalLeft + (originalWidth - self.width)/2; self.bottom = originalBottom; } else { // Calculate my new height CGFloat newHeight = self.width / imageWidthToHeightRatio; self.height = newHeight; self.bottom = originalBottom; } self.contentMode = UIViewContentModeScaleAspectFit; [super setImage:image]; } else { [super setImage:image]; } } @end 
0
Jun 13 '12 at 16:25
source share

If you need to achieve aspectFit and get rid of empty spaces

Do not forget to remove the width limit of your image from the storyboard and enjoy

SelfSizedImageView Class: UIImageView {

 override func layoutSubviews() { super.layoutSubviews() guard let imageSize = image?.size else { return } let viewBounds = bounds let imageFactor = imageSize.width / imageSize.height let newWidth = viewBounds.height * imageFactor let myWidthConstraint = self.constraints.first(where: { $0.firstAttribute == .width }) myWidthConstraint?.constant = min(newWidth, UIScreen.main.bounds.width / 3) layoutIfNeeded() }} 
0
Apr 18 '19 at 14:52
source share

To align the scalable image, use the automatic layout. An example of right alignment after scaling according to UIImageView:

  • Create a UIImageView that contains the image
  • Add automatic restrictions for rights, top, bottom, width
  • Set image:
 myUIImageView.contentMode = .ScaleAspectFit myUIImageView.translatesAutoresizingMaskIntoConstraints = false myUIImageView.image = UIImage(named:"pizza.png") 

The corresponding scalable image of your aspect is now right-aligned in the UIImageView

 +----------------------------------+ | [IMAGE]| +----------------------------------+ 

Change the constraints to align differently within the image.

-four
Nov 12 '16 at 16:45
source share



All Articles