pajevic
pajevic

Reputation: 4667

Force UIView with zero height to lay out its subviews

I have an UIView with some labels in it. The labels have dynamic height depending on the text, and they have vertical spacing constraints to the parent view and to each other, giving the parent view its height. The constraint between the bottom of the last label and the bottom of the parent view is set to have a lower priority.

enter image description here

Additionally, the parent view has a height constraint that I set to 0 in viewDidLoad. This collapses the view and pushes all the labels down, since the last bottom constraint has a lower priority. I then have a button where I toggle the height constraint of the parent view, which opens/closes it:

@IBAction func viewInfoButtonTapped(_ sender: Any) {
    viewInfoButton.isSelected = !viewInfoButton.isSelected
    
    self.infoHeightConstraint.isActive = !self.viewInfoButton.isSelected
    UIView.animate(withDuration: 0.25) {
        self.view.layoutIfNeeded()
    }
}

My issue is that the dynamic height of the labels are not set until I expand the parent view the first time, so instead of an animation where the labels are simply revealed, I get an effect where thy are revealed and grow in height at the same time. After the first expansion, the heights have been set, and subsequent expansions give the correct effect.

How can I force the view to lay out the constraints correctly before it is expanded the first time? I have tried calling setNeedsLayout() and layoutIfNeeded(), but it doesn't seem to have an effect.

Upvotes: 0

Views: 453

Answers (1)

DonMag
DonMag

Reputation: 77690

Set the Vertical Content Compression Resistance priority to Required (1000) on each of your labels:

enter image description here

Or, since you're likely looping through them at run-time to set the text in each, you can do it via code:

label.text = someString
label.setContentCompressionResistancePriority(.required, for: .vertical)

That should fix the initial "stretching" that you don't want.

If you're still seeing stretching (shouldn't, but just in case) you can also call sizeToFit():

label.text = someString
label.setContentCompressionResistancePriority(.required, for: .vertical)
label.sizeToFit()

Upvotes: 1

Related Questions