'UIImageView hugging & compression priority not working properly when new image is inserted

I'm trying to make view like this:

Everything works fine, but when I put image from API to that UIImageView, this happens: UIImageView is stretching even with some Hugging Priority and Compression priority

Code for View:

    let scrollView = UIScrollView()
    let contentView = UIView()

    lazy var posterImage = UIImageView().then {
        $0.contentMode = .scaleAspectFit
        $0.image = UIImage(named: "img_placeholder")    // placeholder image
        
        $0.backgroundColor = .orange
        $0.setContentHuggingPriority(.required, for: .horizontal)
    }
    
    lazy var titleLabel = UILabel().then {
        $0.textColor = .white
        $0.textAlignment = .left
        
        $0.font = UIFont.systemFont(ofSize: 25, weight: .medium)
        $0.numberOfLines = 0
        $0.minimumScaleFactor = 10
        
        $0.setContentHuggingPriority(.required, for: .vertical)
    }
    
    lazy var taglineLabel = UILabel().then {
        $0.numberOfLines = 0
        $0.textColor = .lightGray
        $0.textAlignment = .left
        $0.font = UIFont.systemFont(ofSize: 15, weight: .regular)
    }
    
    lazy var runtimeIconLabel = IconLabel().then {
        $0.icon.image = UIImage(systemName: "clock")
    }
    
    lazy var ratingIconLabel = IconLabel().then {
        $0.icon.image = UIImage(systemName: "star.fill")
        $0.icon.tintColor = .orange
    }
    
    lazy var iconLabels = UIStackView().then {
        $0.addArrangedSubview(runtimeIconLabel)
        $0.addArrangedSubview(ratingIconLabel)
        
        $0.axis = .horizontal
        $0.distribution = .fill
        $0.alignment = .leading
        $0.spacing = 5
    }
    
    lazy var mainInfoLabelStack = UIStackView().then {
        $0.addArrangedSubview(titleLabel)
        $0.addArrangedSubview(taglineLabel)
        $0.addArrangedSubview(UIView())
        $0.addArrangedSubview(iconLabels)
        
        $0.axis = .vertical
        $0.distribution = .fill
        $0.alignment = .leading
        $0.spacing = 5
    }
        
    lazy var mainInfoStackView = UIStackView().then {
        $0.addArrangedSubview(posterImage)
        $0.addArrangedSubview(mainInfoLabelStack)
        
        $0.axis = .horizontal
        $0.distribution = .fill
        $0.alignment = .fill
        $0.spacing = 10
        $0.isLayoutMarginsRelativeArrangement = true
        $0.layoutMargins = UIEdgeInsets.detailViewComponentInset

        posterImage.setContentHuggingPriority(.required, for: .horizontal)
        mainInfoLabelStack.setContentHuggingPriority(.defaultLow, for: .horizontal)

    }

Adding Constraints:

        self.view.addSubview(scrollView)
        scrollView.addSubview(contentView)
        
        scrollView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        contentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalToSuperview()
        }

        contentView.addSubview(mainInfoStackView)

        mainInfoStackView.snp.makeConstraints { make in
            make.top.left.right.equalToSuperview()
            make.height.equalTo(self.view.snp.width).multipliedBy(0.45)
        }

I want to remove unintended margin of UIImageView



Solution 1:[1]

You must set image contentMode to "scaleAspectFill" for the "posterImage" because of dimension:

lazy var posterImage = UIImageView().then {
        $0.contentMode = .scaleAspectFill
        $0.image = UIImage(named: "img_placeholder")    // placeholder image
        
        $0.backgroundColor = .orange
    }

remove the below code

$0.setContentHuggingPriority(.required, for: .horizontal)

and set fix width and height constraint for the image

Solution 2:[2]

A UIImageView has no intrinsic size, until an image has been set. At that point, if you haven't given constraint conditions to control it, UIKit will change its size based on the new image.

You probably want something like this:

posterImage.snp.makeConstraints { make in
    make.width.equalTo(posterImage.snp.height).multipliedBy(0.75)
}

to give the image view a 4:3 ratio.

Adjust that .multipliedBy value to suit your design.


Edit

Here's the result...

Initially, posterImage has a "placeholder" image:

enter image description here

then we set its image to this one:

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Maziar Saadatfar
Solution 2