Search code examples
swiftanimationlayoutuikitconstraints

UIView animation works one time then it doesn't work


I am trying to do an animation for my view but it just works the first time which is isOpen = true. It works but when I call my function again isOpen = false, nothing changes.

Parent view is self (UIView). Child is label (UILabel).

private func expansionView(isOpen: Bool) {
    if isOpen {
        label.backgroundColor = .white
        NSLayoutConstraint.activate([
             label.centerYAnchor.constraint(equalTo: self.topAnchor),
             label.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 15),
         ])
        
        UIView.animate(withDuration: 1, animations: {
            self.layoutIfNeeded()
        }) { (_) in
            
        }
    } else {
        label.backgroundColor = .clear
        NSLayoutConstraint.activate([
             label.centerYAnchor.constraint(equalTo: self.centerYAnchor),
             label.leadingAnchor.constraint(equalTo: self.leadingAnchor , constant: 15),
         ])

        UIView.animate(withDuration: 1, animations: {
            self.layoutIfNeeded()
        }) { (_) in
            print("Animation Completed!!!")
        }
    }
}

Solution

  • You need to have two constraints to make one of them active. You can also animate changing label's background color to clear. And you can simplify your function like below.

    // define both vertical constraints
    var constraintToCenterYAnchor: NSLayoutConstraint!
    var constraintToTopAnchor: NSLayoutConstraint!
    
    // where you init your view..
    init() {
        // init your constraints
        constraintToTopAnchor = label.centerYAnchor.constraint(equalTo: topAnchor)
        constraintToCenterYAnchor = label.centerYAnchor.constraint(equalTo: centerYAnchor)
    
        // set and activate other constraints once.
        label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 15).isActive = true
    
        // update background color of the label
        label.backgroundColor = .clear
        label.layer.backgroundColor = UIColor.white.cgColor
    }
    
    // simplify your function
    private func expansionView(_ isOpen: Bool) {
        constraintToTopAnchor.isActive = isOpen
        constraintToCenterYAnchor.isActive = !isOpen
        
        UIView.animate(withDuration: 1) {
            self.label.layer.opacity = isOpen ? 1.0 : 0.0
            self.layoutIfNeeded()
        }
    }