[Swift]オリジナル画像の縦横比を維持したままUIImageViewに隙間なくフル表示する方法

Swift

はじめに

この記事ではUIImageViewの横幅をディスプレイの幅に合わせ、かつ横幅の比率を1とした場合のオリジナル画像と同じ高さの比率で表示する方法を紹介しています。

環境

  • Swift5
  • Xcode12.4
  • iOS13

実装方法

結論から書くと、UIImageViewの高さ=UIImageViewの横幅✕(画像の高さ/画像の幅)で計算して設定しています。

コード

FlexibleHeightImageViewとしてクラスを作成しました。
使い方のサンプルとしてSampleFlexibleHeightImageViewControllerも記載しておきます。

import UIKit

class FlexibleHeightImageView: UIView {
    
    private var imageView = UIImageView()
    
    @IBInspectable
    public var image: UIImage? {
        didSet {
            imageView.image = image
            updateImageViewConstraints()
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        initialize()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        initialize()
    }
    
    private func initialize() {
        addSubview(imageView)
        imageView.contentMode = .scaleAspectFit
        imageView.translatesAutoresizingMaskIntoConstraints = false
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        if let img = image {
            let height = self.frame.size.width * (img.size.height / img.size.width)
            imageView.heightAnchor.constraint(equalToConstant: height).isActive = true
        }
    }
    
    private func updateImageViewConstraints() {
        imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
    }
}
import UIKit

class SampleFlexibleHeightImageViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        let fImageView = FlexibleHeightImageView(frame: .zero)
        view.addSubview(fImageView)
        fImageView.translatesAutoresizingMaskIntoConstraints = false
        fImageView.image = UIImage(named: "img")

        fImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200).isActive = true
        fImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
        fImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
    }
}

コードの説明

imageViewのcontentModescaleAspectFitとしています。
こうすることで画像全体をimageViewに表示するように設定します。このままでは画像全体が収まるように表示されるため、画像とimageView間に余白ができてしまいます。余白が空かないように画像全体をimageViewに表示するために次の計算式で動的に高さを設定します。

imageView.contentMode = .scaleAspectFit

画像が取得できた場合にUIImageViewの高さ=UIImageViewの横幅✕(画像の高さ/画像の幅)で横幅比を1とし、それに対して高さ比を計算して動的に設定しています。

let height = self.frame.size.width * (img.size.height / img.size.width)
imageView.heightAnchor.constraint(equalToConstant: height).isActive = true

fImageView(FlexibleHeightImageView)の高さを固定値としないことがポイントとなります。
高さ200とかしてしまうとその値で表示されてしまうのでお気をつけください。

imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200).isActive = true
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true

まとめ

仕事をしているとわりかし要望があるかなと思いますので役に立ったら嬉しいです。

コメント

タイトルとURLをコピーしました