Wait for Swift animation to complete before execut

2019-01-22 06:47发布

问题:

I am trying to animate a UIImageView and then hide the image view after animation is complete. However the imageview gets hidden before the animation is completed. I looked at similar questions and they recommend implementing an animation listener or executing the .hidden code within the animation code upon completion however I'm not sure how to affect this within the shakeView() function below.

How do I show the shake animation and hide the image view only after the animation is complete?

Animation is called using the following code:

shakeView(image1!)
shakeView(image2)
image1!.hidden = true
image2.hidden = true

The animation function itself looks like this:

func shakeView(iv: UIImageView){
    var shake:CABasicAnimation = CABasicAnimation(keyPath: "position")
    shake.duration = 0.1
    shake.repeatCount = 2
    shake.autoreverses = true

    var from_point:CGPoint = CGPointMake(iv.center.x - 5, iv.center.y)
    var from_value:NSValue = NSValue(CGPoint: from_point)

    var to_point:CGPoint = CGPointMake(iv.center.x + 5, iv.center.y)
    var to_value:NSValue = NSValue(CGPoint: to_point)

    shake.fromValue = from_value
    shake.toValue = to_value
    iv.layer.addAnimation(shake, forKey: "position")
}

回答1:

You can use a CATransaction to call a completion block after the animation completes.

func shakeView(iv: UIImageView){

    CATransaction.begin()
    CATransaction.setCompletionBlock({
        iv.hidden = true
    })
    var shake:CABasicAnimation = CABasicAnimation(keyPath: "position")
    shake.duration = 0.1
    shake.repeatCount = 21
    shake.autoreverses = true

    var from_point:CGPoint = CGPointMake(iv.center.x - 5, iv.center.y)
    var from_value:NSValue = NSValue(CGPoint: from_point)

    var to_point:CGPoint = CGPointMake(iv.center.x + 5, iv.center.y)
    var to_value:NSValue = NSValue(CGPoint: to_point)

    shake.fromValue = from_value
    shake.toValue = to_value
    iv.layer.addAnimation(shake, forKey: "position")
    CATransaction.commit()
}

Or you can also group both animations together in a CATransaction as follows.

func shakeView(iv: UIImageView){
    var shake:CABasicAnimation = CABasicAnimation(keyPath: "position")
    shake.duration = 0.1
    shake.repeatCount = 21
    shake.autoreverses = true

    var from_point:CGPoint = CGPointMake(iv.center.x - 5, iv.center.y)
    var from_value:NSValue = NSValue(CGPoint: from_point)

    var to_point:CGPoint = CGPointMake(iv.center.x + 5, iv.center.y)
    var to_value:NSValue = NSValue(CGPoint: to_point)

    shake.fromValue = from_value
    shake.toValue = to_value
    iv.layer.addAnimation(shake, forKey: "position")
}

override func viewDidLoad() {
    CATransaction.begin()

    CATransaction.setCompletionBlock({
        self.image1.hidden = true
        self.image2.hidden = true
    })
    shakeView(image1)
    shakeView(image)
  CATransaction.commit()
}


回答2:

As Paulw11 alluded to in his comment, you can use the animationDidStop: method mentioned in the docs. But furthermore, you should add a key to you CABasicAnimation/CAAnimation objects such that your animationDidStop: method knows which one in particular has completed.

So in your shake method add a value-key pair to identify the animation and set the delegate to self, ex:

func shakeView(iv: UIImageView){

    var shake:CABasicAnimation = CABasicAnimation(keyPath: "position")
    shake.duration = 0.1
    shake.repeatCount = 2
    shake.autoreverses = true

    // Add these two lines:
    shake.setValue("shake", forKey: "animationID")
    shake.delegate = self

    // ...

Then add the animationDidStop: delegate method to alert you as to when the animation is complete so you can start executing your code:

override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
    // Unwrap the optional value for the key "animationID" then
    // if it's equal to the same value as the relevant animation,
    // execute the relevant code
    if let animationID: AnyObject = anim.valueForKey("animationID") {
        if animationID as NSString == "shake" {
            // execute code
        }
    }
}