Search code examples
iosswiftautolayoutuiviewanimation

UIView animation with autolayout and child views


I have a weird problem that seems to be fairly easy to solve. I think I could use some workaround to be able to have the behavior that I want but I want to know if there is a better way to do it.

I have a view called contentView (blue in the image) that it will expand its height using a UIView.animation, this is no problem at all and works as expected.

The problem here is that this view has a child component (a button) that has an autolayout constraint to its bottom equal to 22 like this:

contentView with the button

This is the autolayout constraint:

enter image description here

If I do the height resize without the animation it works fine, the view height change and the button are always 22 points of the bottom of the contentView. But when I use an animation to make this change more smoothy and user-friendly the button moves to the end position before the animation even start.

enter image description here

I want to know how I could achieve a smooth animation here but with the button moving along its parent view

The part of the code that handles the animation is pretty straightforward but I'll post it in here:

@IBAction func openDetail(_ sender: ExpandCourseDetail) {
        let rotation = sender.getOpen() ? CGAffineTransform.identity : CGAffineTransform(rotationAngle: CGFloat.pi)
        UIView.animate(withDuration: 0.5, delay: 0.1, options: [.curveEaseInOut], animations: {
            sender.transform = rotation
        }, completion: {
            success in
            sender.setOpen(!sender.getOpen())
        })
        UIView.animate(withDuration: 1.0, delay: 0.5, options: [.curveEaseInOut], animations: {
            self.contentView.frame.size.height = sender.getOpen() ? self.contentView.frame.height - 300 : self.contentView.frame.height + 300
        }, completion: nil)
    }

As a side note, the button itself has an animation that rotates the button 180 degrees to show the user that the view is expanding.

Thank you so much for your help.


Solution

  • It's super easy with constraints, just create a superView height constraint IBOutlet and change its constant value.

    @IBAction func btnPressed(_ sender: UIButton) {
        self.toggleButton.isSelected = !sender.isSelected
    
        //Animation starts here
        self.view.layoutIfNeeded()
        UIView.animate(withDuration: 0.7) {
    
            if self.toggleButton.isSelected {
                //transform button
                self.toggleButton.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
    
                //change your ParentView height to desired one
                self.constContentViewHeight.constant = self.view.frame.size.height - 220
                self.view.layoutIfNeeded()
            } else {
    
                self.toggleButton.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi*2))
                // Set height constraint to original value
                self.constContentViewHeight.constant = 250
                self.view.layoutIfNeeded()
            }
        }
    
    }
    

    I have created a demo, check it out.

    demo