I have a UIImageView
and the user is able to download UIImages
in various formats. The issue is that I need the UIImageView
to resize
I spent many hours trying to find a solution to the same problem you're having and this is the only solution that worked for me (Swift 4, xCode 9.2):
class ScaledHeightImageView: UIImageView {
override var intrinsicContentSize: CGSize {
if let myImage = self.image {
let myImageWidth = myImage.size.width
let myImageHeight = myImage.size.height
let myViewWidth = self.frame.size.width
let ratio = myViewWidth/myImageWidth
let scaledHeight = myImageHeight * ratio
return CGSize(width: myViewWidth, height: scaledHeight)
}
return CGSize(width: -1.0, height: -1.0)
}
}
Add the class to the project and set the UIImageView to the custom class ScaledHeightImageView. The image view's content mode is Aspect Fit.
My problem is the same as the one stated in this post. Inside my prototype TableViewCell's ContentView, I have a vertical StackView constrained to each edge. Inside the StackView there was a Label, ImageView and another Label. Having the ImageView set to AspectFit was not enough. The image would be the proper size and proportions but the ImageView didn't wrap the actual image leaving a bunch of extra space between the image and label (just like in the image above). The ImageView height seemed to match height of the original image rather than the height of the resized image (after aspectFit did it's job). Other solutions I found didn't completely resolve the problem for various reasons. I hope this helps someone.
This can easily be converted to use IBOutlets if desired. My use-case involved programmatically adding imageViews. This is very reliable. Just create a new file in your project and add the code below.
import UIKit
/// Resizeable Image View that takes a max height and max width
/// Will resize the imageView to best fit for the aspect ratio of the image,
/// With the given space provided.
public class ResizeableImageView: UIImageView {
private var widthConstraint: NSLayoutConstraint?
private var heightConstraint: NSLayoutConstraint?
// MARK: - INITIALIZERS:
public override init(image: UIImage?) {
super.init(image: image)
}
/// Given the max width and height, resizes the imageView to fit the image.
/// - IMPORTANT: This subclass adds a height and width constraint.
/// - Parameters:
/// - image: (UIImage?) The image to add to the imageView.
/// - maxWidth: (CGFloat) The max width you would like the imageView to grow to.
/// - maxHeight: (CGFloat) The max height you would like the imageView to grow to.
convenience init(image: UIImage?, maxWidth: CGFloat, maxHeight: CGFloat) {
self.init(image: image)
widthConstraint = constrain(width: maxWidth)
heightConstraint = constrain(height: maxHeight)
}
@available (*, unavailable) required internal init?(coder aDecoder: NSCoder) { nil }
// MARK: - VARIABLES:
/// The maximum width that you want this imageView to grow to.
private var maxWidth: CGFloat {
get { widthConstraint?.constant ?? 0 }
set { widthConstraint?.constant = newValue }
}
/// The maximum height that you want this imageView to grow to.
private var maxHeight: CGFloat {
get { heightConstraint?.constant ?? 0 }
set { heightConstraint?.constant = newValue }
}
private var maxAspectRatio: CGFloat { maxWidth / maxHeight }
override public var intrinsicContentSize: CGSize {
guard let classImage = self.image else { return frame.size }
let imageWidth = classImage.size.width
let imageHeight = classImage.size.height
let aspectRatio = imageWidth / imageHeight
// Width is greater than height, return max width image and new height.
if imageWidth > imageHeight {
let newHeight = maxWidth/aspectRatio
self.widthConstraint?.constant = maxWidth
self.heightConstraint?.constant = newHeight
return CGSize(width: maxWidth, height: newHeight)
}
// Height is greater than width, return max height and new width.
if imageHeight > imageWidth {
// If the aspect ratio is larger than our max ratio, then using max width
// will be hit before max height.
if aspectRatio > maxAspectRatio {
let newHeight = maxWidth/aspectRatio
self.widthConstraint?.constant = maxWidth
self.heightConstraint?.constant = newHeight
return CGSize(width: maxWidth, height: newHeight)
}
let newWidth = maxHeight * aspectRatio
self.widthConstraint?.constant = newWidth
self.heightConstraint?.constant = maxHeight
return CGSize(width: newWidth, height: maxHeight)
}
// Square image, return the lesser of max width and height.
let squareMinimumValue = min(maxWidth, maxHeight)
self.widthConstraint?.constant = squareMinimumValue
self.heightConstraint?.constant = squareMinimumValue
return CGSize(width: squareMinimumValue, height: squareMinimumValue)
}
}
let imageView = ResizeableImageView(image: image, maxWidth: 250, maxHeight: 250)