12

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).

Community
  • 1
  • 1
James P
  • 4,786
  • 2
  • 35
  • 52

1 Answers1

10

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

ilovecomputer
  • 4,238
  • 1
  • 20
  • 33
  • How would I do this if I want 1 subview to have a fixed width, and the other to fill the available space? (I want to toggle between the views) I tried removing / adding constraints in the animation block and it works, but breaks other constraints. – James P Jun 08 '16 at 15:06
  • Actually adding and removing the constraints works well, but I had to lower the priority to stop other constraints breaking. – James P Jun 08 '16 at 15:27