I have some issues with auto layout when building view programmatically.
There is a vertical UIStackView with several elements inside, mainly labels and images. After setting properties on stackView and imageView, as a result I get something similar to image 1 below (white spaces on top and bottom of the image; the smaller screen size the bigger white spaces) while I would like to get something more similar to image 2 (without white spaces around image).
1:
2:
I was reading some tutorials on how to properly set the stackView, its distribution and alignment and as a result in my StackView properties are set like this:
myStackView.axis = .vertical
myStackView.distribution = .fill
myStackView.alignment = .fill
myStackView.spacing = 12
myStackView.contentMode = .scaleAspectFit
and on ImageView before I add it as an arranged subview, I set:
myImageView.contentMode = .scaleAspectFit
myImageView.autoresizesSubviews = true
myImageView.sd_setImage(with: URL(string: image))
myImageView.setContentHuggingPriority(251, for: .horizontal)
myImageView.setContentHuggingPriority(500, for: .vertical)
myImageView.setContentCompressionResistancePriority(750, for: .horizontal)
myImageView.setContentCompressionResistancePriority(750, for: .vertical)
I did not change CHP and CCRP on labels above and under the imageView.
I was trying to manipulate with content hugging priority and content compressions resistance priority but it did not change anything. Any ideas what I do wrong?
I suspect the problem here as is that the hugging and compression-resistance priorities apply to the view's intrinsic content size, and the intrinsic content size of a UIImageView
is the natural size of the image. But you want the image to be scaled to fit the width of the screen, which means that (in general) you don't want the image view's size to be the natural size of its image. Thus the hugging and compression-resistance priorities will not help you.
What you need to do is add two constraints:
Constrain the image view's width to equal the stack view's width. You can do this in the storyboard or in code. In code:
myImageView.widthAnchor.constraint(equalTo: myStackView.widthAnchor).isActive = true
Constrain the image view's aspect ratio to match the image's aspect ratio. If you change the image at runtime, you need to do this in code, like this:
// Instance variable:
var imageAspectRatioConstraint: NSLayoutConstraint?
// When you set the image:
imageAspectRatioConstraint?.isActive = false
imageAspectRatioConstraint = myImageView.widthAnchor.constraint(
equalTo: myImageView.heightAnchor,
multiplier: myImageView.image!.size.width / myImageView.image!.size.height)
imageAspectRatioConstraint!.isActive = true
These two required constraints will force the image view to be exactly the right height to perfectly contain the scaled image.
You may still run into trouble if you have constrained the height of the stack view to match the height of some other view—for example, your top-level view. (If your stack view is your top-level view, it is effectively constrained to fill the screen.) In that case, the stack view will stretch or shrink at least one of its arranged subviews as needed to fill that height.
If none of the arranged subviews has a flexible height, then auto layout may end up breaking the image view's aspect ratio constraint so it can stretch the image view to fill the needed space. Or it may stretch some other view that you don't want stretched.
If that's happening, you have three options:
Remove the constraint that's forcing the stack view to fill the height of some other view. Then auto layout will set the height of the stack view to exactly contain its arranged subviews at their preferred sizes (based on constraints or intrinsic content size).
Lower the vertical hugging and/or compression resistance priority of one or more arranged subviews that you want resized to fill the required height.
Add a “padding” UIView
to the stack view to absorb the additional height. Set its background color to nil or .clear
so it's not visible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With