1

I have an UIImageView inside UIView which is inside an horizontal UIStackView (with .fillEqually option). Horizontal UIStackView has two views always. Horizontal UIStackView gets its height from the Its' highest sub UIView.

What I want to achieve: In the example screenshot, UIImageView has a bigger size when you consider with the multiline views because of its image size. However, I want that image view shrinks to the size that fits left (multiline label) view. This is shown in the second screenshot. Image should has a height of which I show via red oval line on the right side.

UIImageView with label Class:

@IBDesignable class LabelWithImage: UIView {

var topMargin: CGFloat = 0.0
var verticalSpacing: CGFloat = 10.0
var bottomMargin: CGFloat = 0.0

@IBInspectable var labelText: String = "" { didSet { updateView() } }
@IBInspectable var image: UIImage = UIImage(named: "harcamagrafik")! { didSet { updateView() } }

fileprivate var label: UILabel!
fileprivate var imageView: UIImageView!

override init(frame: CGRect) {
    super.init(frame: frame)
    setUpView()
}

required public init?(coder: NSCoder) {
    super.init(coder:coder)
    setUpView()
}

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    setUpView()
}

func setUpView() {

    label = UILabel()
    label.font = UIFont.init(name: "Metropolis-Medium", size: 12)
    label.numberOfLines = 1
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.textColor = UIColor.init(rgb: 0x9B9B9B)

    imageView = UIImageView(image: image)
    imageView.contentMode = .scaleAspectFill
    imageView.clipsToBounds = true

    addSubview(label)
    addSubview(imageView)

    label .translatesAutoresizingMaskIntoConstraints = false
    imageView.translatesAutoresizingMaskIntoConstraints = false
    setContentHuggingPriority(.init(rawValue: 1000.0), for: .vertical)
    setContentCompressionResistancePriority(.init(rawValue: 10.0), for: .vertical)

    label.leftAnchor.constraint(equalTo: leftAnchor, constant: 0.0).isActive = true
   // imageView.leftAnchor.constraint(equalTo: leftAnchor, constant: 0.0).isActive = true

    label.rightAnchor.constraint(equalTo: rightAnchor, constant: 0.0).isActive = true
   // imageView.rightAnchor.constraint(equalTo: rightAnchor, constant: 0.0).isActive = true

    imageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
    label.topAnchor.constraint(equalTo: topAnchor, constant: topMargin).isActive = true
    imageView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: verticalSpacing).isActive = true
    bottomAnchor.constraint(equalTo: imageView.bottomAnchor, constant: bottomMargin).isActive = true

    // call common "refresh" func
    updateView()
}

func updateView() {
    label.text = labelText
    accessibilityIdentifier = labelText
    imageView.image = image
    label.sizeToFit()
}
}

Horizontal StackView:

private let topHorizontalStackView: UIStackView = {
let s = UIStackView()
s.distribution = .fillEqually
s.spacing = 10
s.axis = .horizontal
s.alignment = .fill
s.translatesAutoresizingMaskIntoConstraints = false
return s
}()

EDIT I tried to set a height constraint to my LabelWithImage view. Now, It looks ok but when I open the debugger, It says that height is ambiguous for the view.

leftView.layoutIfNeeded() //It is the view with multilineLabel.
view.heightAnchor.constraint(equalToConstant: leftView.bounds.height).isActive = true

Example View

What I want shown in screenshot:

ss2

EDIT 2 After I give priority to label as @Don said and set compression to low on image view, I got below result. Below code is still active by the way

leftView.layoutIfNeeded() //It is the view with multilineLabel. view.heightAnchor.constraint(equalToConstant: leftView.bounds.height).isActive = true

If I give specific constant to labelWithImageView as (40 is UIStackView top and bottom insets);

view.heightAnchor.constraint(equalToConstant: leftView.bounds.height - 40).isActive = true

Views inside top vertical UIStackView shows ambitious layout. (You can't see that views inside screenshots because I guess those are not related.) ss3

Emre Önder
  • 2,408
  • 2
  • 23
  • 73
  • You need to provide more information about the constraints used for all views. From what you've shown, you are not setting any height constraint on the image view, so how are you expecting it to be sized? – DonMag Nov 11 '19 at 18:17
  • I want Its superview has an height of multiline view. How can I achieve it? – Emre Önder Nov 12 '19 at 05:36

1 Answers1

0

Well, it just looks like your constraints are wrong, here I've made an example with screen attached so you can recreate my constraints

Here's an explanation: in left view set your own constraints to fill the view (check for ambiguity since right view is supposed to get the size from the left one), set all labels inside it with vertical content hugging priority to 1000

on right one you simply need to set the title vertical content hugging priority to 1000 (+ basic needed constraints like leading, trailing and top to fill the view) and viola, image will morph into whatever size needed to match left view's size.

enter image description here

Don
  • 490
  • 3
  • 9
  • I tried but It doesn't work in my case. My left view is a view which consist of a vertical UIStackview and UIStackview has arranged subviews of UIViews. That UIViews has two UILabel with constraint of top, leading, trailing and bottom. – Emre Önder Nov 12 '19 at 09:09
  • I give `view.heightAnchor.constraint(equalTo: leftView.heightAnchor).isActive = true` to my labelWithImage view. Now box has correct size but Imageviews bottom goes under the box instead of smalling. – Emre Önder Nov 12 '19 at 09:15
  • I think my problem is that leftView is a UIStackview which has a .fill option. – Emre Önder Nov 12 '19 at 09:23
  • Not really, as long as you set label vertical content hugging to 1000 and set image compression resistance to 250 It will act fine, just tested what I made with a stackview filled with 3 of my own example left views, image expanded just fine, but I had to change the image's compression resistance to 250 for it to shrink to left view's size. Add this to your code imageView.setContentCompressionResistancePriority(.defaultLow, for: .vertical) – Don Nov 12 '19 at 09:31
  • Are u giving height anchor or height constraint to rightView? – Emre Önder Nov 12 '19 at 10:55
  • No, it fits the size of left view's height since they are under a stackview with .fill option. Try running View debugger to see if the image's frame is outside the box or image's clip to bounds isn't working properly. – Don Nov 12 '19 at 11:52