0
votes

I have only ever used auto layout in IB and was wondering how I can go about programatically setting a UIImageView to centre both vertically and horizontally after resizing it.

Basically the UIImageView contains a photo and the UIImageView is then resized to fit the photo. After this process I was wondering how I can go about setting the constraints so that the image is correctly positioned.

The code below shows the process of loading the image and setting the UIImageView. At the minute the positioning is done manually without the use of AutoLayout.

- (void)setupUI {

CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;

self.imageViewCanvas.translatesAutoresizingMaskIntoConstraints = YES;
[self.imageViewCanvas setFrame:CGRectMake(0, 0, screenWidth, screenHeight)];

self.btnTool.alpha = 0;

}

- (void)loadNewImageIntoCanvas {

[self.imageViewCanvas setImage:self.imageToEdit];

[self imageSizeAfterAspectFit:self.imageViewCanvas];

[UIImageView animateWithDuration:0.2 animations:^{
    self.imageViewCanvas.alpha = 1;
} completion:^(BOOL finished) {

    [self showBTNTool];

}];


}

- (void)resetCanvasSize {

CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;

[self.imageViewCanvas setFrame:CGRectMake(0, 0, screenWidth, screenHeight)];

}

-(CGSize)imageSizeAfterAspectFit:(UIImageView*)imgview{

CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;

CGRect newSize = [self frameForImage:self.imageViewCanvas.image inImageViewAspectFit:self.imageViewCanvas];

float newwidth = newSize.size.width;
float newheight = newSize.size.height;

float new_x = (screenWidth / 2) - (newwidth / 2);
float new_y = (screenHeight / 2) - (newheight / 2);

[self.imageViewCanvas setFrame:CGRectMake(new_x, new_y, newwidth, newheight)];

return CGSizeMake(0, 0);

}

-(CGRect)frameForImage:(UIImage*)image inImageViewAspectFit:(UIImageView*)imageView {

float imageRatio = image.size.width / image.size.height;

float viewRatio = imageView.frame.size.width / imageView.frame.size.height;

if(imageRatio < viewRatio)
{
    float scale = imageView.frame.size.height / image.size.height;

    float width = scale * image.size.width;

    float topLeftX = (imageView.frame.size.width - width) * 0.5;

    return CGRectMake(topLeftX, 0, width, imageView.frame.size.height);
}
else
{
    float scale = imageView.frame.size.width / image.size.width;

    float height = scale * image.size.height;

    float topLeftY = (imageView.frame.size.height - height) * 0.5;

    return CGRectMake(0, topLeftY, imageView.frame.size.width, height);
}
}
2
Why don't you just say self.imageViewCanvas.translatesAutoresizingMaskIntoConstraints = YES; then set it's frame?beyowulf
I am doing that now but I get warning messages when I run the app. Along the lines of "Unable to simultaneously satisfy constraints." Updated question to show how I do this.ORStudios
With the result being that the image is not in the right place?beyowulf
No the image is in the correct place, I was looking at switching this over so I can let AutoLayout manage the positioning after resizing the image.ORStudios
Do you have complex interface that requires dependent positioning? Auto layout seems like over kill for what you're doing. Setting translatesAutoresizingMaskIntoConstraints to true cause the auto layout engine to create constraints, sometime conflicting, but it knows which ones to break to place the element in its proper frame.beyowulf

2 Answers

4
votes

In order to center image view using auto layout you need constraints for width and height too. Not only centerXAnchor and centerYAnchor. Because UIImageView doesn't have intrinsicContentSize.

(Note that centerXAnchor and centerYAnchor methods are only available on iOS 9.0+)

self.imageView.translatesAutoresizingMaskIntoConstraints = NO;

[self.imageView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
[self.imageView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES;

[self.imageView.widthAnchor constraintEqualToConstant:self.imageWidth].active = YES;
[self.imageView.heightAnchor constraintEqualToConstant:self.imageHeight].active = YES;
1
votes

Pretty sure you can say something like this.

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.imageViewCanvas attribute: NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.imageViewCanvas attribute: NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];

This is not enough to satisfy all the necessary constraints though. IMO, it's easier to set constraints in IB, if you need to dynamically change the constraints, create an IBOutlet for them, and change their constant property.

For example, you can create one IBOutlet for your image view's height constraint, call it imageViewHeightConstraint, another for your image view's width constraint, call it imageViewWidthConstraint, then you can say:

self.imageViewHeightConstraint.constant = 400;
self.imageViewWidthConstraint.constant = 400;