Search code examples
swiftswift4swift4.2

Swift: Two animations once after another


I have this little animation issue, where I get stuck. I want to show two animation, one after the other (first swiping a card from the button to the center and then fliping it). So I'm using the completion in the UIView.animate method, to trigger the second animation, once the first animation is done. But in the simulator it shows every time only the second animation. Can somebody help out? Thanks a lot

UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut, animations: {
    let animation:CABasicAnimation = CABasicAnimation(keyPath: "position")
    animation.fromValue = NSValue(cgPoint:CGPoint(x: self.imgBackOfTheCard.frame.midX, y: 1200))
    animation.toValue = NSValue(cgPoint:CGPoint(x: self.imgBackOfTheCard.frame.midX, y: self.imgBackOfTheCard.frame.midY))
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    animation.duration = 1
    self.imgBackOfTheCard.layer.add(animation, forKey: "position")
    }, completion: { (finished: Bool) in
        UIView.animate(withDuration: 1, delay: 1, options: .curveLinear, animations: {
            let transitionOptionsLeft: UIView.AnimationOptions = [.transitionFlipFromLeft, .showHideTransitionViews]
            UIView.transition(from: self.imgBackOfTheCard, to: self.imgFrontCard, duration: 1, options: transitionOptionsLeft, completion: nil)
        })
})

Solution

  • You are mixing CA animation and UIView animation.

    The first animation is a CABasicAnimation. UIView.animate doesn't recognise it, so the first animation is "done" (as far as UIView.animate is concerned) immediately and the completion closure is called. Now you do another UIView animation. But actually, the first animation is just starting, so the second animation takes over and you only see the second one.

    To fix this, you should move the first animation out of the UIView.animate block:

    let animation:CABasicAnimation = CABasicAnimation(keyPath: "position")
    animation.fromValue = NSValue(cgPoint:CGPoint(x: self.imgBackOfTheCard.frame.midX, y: 1200))
    animation.toValue = NSValue(cgPoint:CGPoint(x: self.imgBackOfTheCard.frame.midX, y: self.imgBackOfTheCard.frame.midY))
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    animation.duration = 1
    self.imgBackOfTheCard.layer.add(animation, forKey: "position")
    

    And then wait for 1 second, then do the second animation:

    DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
       // do your second animation here.
    })
    

    Upon further inspection, the first animation doesn't have to be a CABasicAnimation. It can be created with UIView.animate as well. Just set the frame property.