Skip to content

Instantly share code, notes, and snippets.

@marcc-orange
Last active April 5, 2023 09:22
Show Gist options
  • Save marcc-orange/e309d86275e301466d1eecc8e400ad00 to your computer and use it in GitHub Desktop.
Save marcc-orange/e309d86275e301466d1eecc8e400ad00 to your computer and use it in GitHub Desktop.
An image view that can computes its intrinsic height from its width while preserving aspect ratio
import UIKit
/// An image view that computes its intrinsic height from its width while preserving aspect ratio
/// Source: https://stackoverflow.com/a/48476446
class ScaledHeightImageView: UIImageView {
// Track the width that the intrinsic size was computed for,
// to invalidate the intrinsic size when needed
private var layoutedWidth: CGFloat = 0
override var intrinsicContentSize: CGSize {
layoutedWidth = bounds.width
if let image = self.image {
let viewWidth = bounds.width
let ratio = viewWidth / image.size.width
return CGSize(width: viewWidth, height: image.size.height * ratio)
}
return super.intrinsicContentSize
}
override func layoutSubviews() {
super.layoutSubviews()
if layoutedWidth != bounds.width {
invalidateIntrinsicContentSize()
}
}
}
@pepasflo
Copy link

pepasflo commented Aug 7, 2019

Thanks so much!

Here's a slightly refactored version:

/// An image view that computes its intrinsic height from its width while preserving aspect ratio
// Based on https://gist.github.com/marcc-orange/e309d86275e301466d1eecc8e400ad00
public class DerivedHeightImageView: UIImageView {

    public override var intrinsicContentSize: CGSize {
        previousLayoutWidth = bounds.width

        guard let image = self.image else {
            return super.intrinsicContentSize
        }

        return CGSize(
            width: bounds.width,
            height: bounds.width / image.size.aspectRatio
        )
    }

    public override func layoutSubviews() {
        super.layoutSubviews()
        if previousLayoutWidth != bounds.width {
            invalidateIntrinsicContentSize()
        }
    }

    // Track the width that the intrinsic size was computed for,
    // to invalidate the intrinsic size when needed
    private var previousLayoutWidth: CGFloat = 0
}

extension CGSize {
    public var aspectRatio: CGFloat {
        return width / height
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment