iosswiftuiviewnslayoutconstraintanimatewithduration

Swift UIView frame not properly updating within animateWithDuration


I'm attempting to update a UIView's position using animateWithDuration. When the animation starts occurring, the UIView begins updating, but then the completion makes it jump to the correct position. This is telling me that the setting of the UIView's frame is not getting set correctly, but I'm not seeing why. Here is the code:

func showInfoView() {

    infoView.hidden = false
    let newPosition = self.view.frame.height - (self.infoView.frame.height + 260)

    UIView.animateWithDuration(2.0, animations: {
        // Set the view to have the new y position
        self.infoView.frame.origin.y = newPosition
        }, completion: { finished in

            // Remove previous constraint
            if (self.hintConstraint != nil) {
                self.view.removeConstraint(self.hintConstraint)
            }

            // Create the new constraint
            self.hintConstraint = NSLayoutConstraint(item: self.infoView, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1, constant: newPosition)
            self.view.addConstraint(self.hintConstraint)
    })
}

Could anyone help me understand why the y position is not getting set properly within the code?


Solution

  • If you're trying to animate with constraints, you should instead change the constraint and then call layoutIfNeeded in the animation block, on the parent view.

    1) Set new constraint outside of the animation block

    2) Within animation block, call layoutIfNeeded on parent view.

    func showInfoView() {
    
        infoView.hidden = false
        let newPosition = self.view.frame.height - (self.infoView.frame.height + 260)
        self.hintConstraint = NSLayoutConstraint(item: self.infoView, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1, constant: newPosition)
    
        UIView.animateWithDuration(2.0, animations: {
            self.view.layoutIfNeeded()
        })
    }