James P
James P

Reputation: 4850

How do I get a UIStackView to update its layout?

I have a UIStackView with 5 subviews. I want to be able to animate the width of these subviews by updating their intrinsicContentSize or updating their constraints. How can I make the stackView redraw after updating the subview's layout?

        UIView.animateWithDuration(0.3, animations: {
            viewToResize.compressed = true //changes intrinsicContentSize
            viewToResize.invalidateIntrinsicContentSize()
            self.stackView.layoutIfNeeded() //makes no difference
            anotherSubview.hidden = true //adding this makes everything work
})

I have tried various ways of trying to get the stackView to update, but nothing happens. The only way I can make it work is if I show/hide another subview inside the animation block, then the new layout is animated correctly, but I don't want to do this.

I have seen this question Animating UIStackView arrangedSubview content size change but the suggested answer does not work (nothing animates).

Upvotes: 12

Views: 25918

Answers (1)

ilovecomputer
ilovecomputer

Reputation: 4738

You don't need viewToResize.invalidateIntrinsicContentSize(), update constraint of your subviews instead. In the code below, we have two subviews in the stackView, and we create a widthConstraint outlet from storyboard. Then we can animate the width of the subview by updating the constant of widthConstraint in animation block. Note: If a view is contained in a stack view and you try to modify the view frame, it should not change

class ViewController: UIViewController {
    @IBOutlet var widthConstraint: NSLayoutConstraint!

    @IBOutlet var stackView: UIStackView!
    var compressed: Bool = true

    @IBOutlet var start: UIButton!

    @IBAction func onStart(sender: UIButton) {
        UIView.animateWithDuration(3.0,
                                   delay: 0.0,
                                   usingSpringWithDamping: 0.3,
                                   initialSpringVelocity: 10.0,
                                   options: .CurveLinear,
                                   animations: { () -> Void in
                                    //self.stackView.invalidateIntrinsicContentSize()
                                    self.widthConstraint.constant = (self.compressed == false) ? 100.0 : 200.0
                                    self.compressed = !self.compressed
                                    self.view.layoutIfNeeded()
            }, completion: nil)
    }

For more details, you can have a look at this great blog UIStackView, Auto Layout and Core Animation

Upvotes: 10

Related Questions