简体   繁体   中英

Auto Layout on UIStackView with UIImageView inside - iOS Swift

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM