在执行代码之前,等待Swift动画完成

时间:2022-08-23 19:35:00

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.

我正在尝试动画一个UIImageView,然后在动画完成后隐藏图像视图。然而,在动画完成之前,imageview会被隐藏。我研究了类似的问题,他们建议在动画代码完成时实现一个动画监听器或在动画代码中执行.hidden代码,但是我不确定如何在下面的shakeView()函数中影响这一点。

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")
}

2 个解决方案

#1


54  

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

您可以使用CATransaction在动画完成后调用完成块。

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.

或者您也可以将这两个动画合并到一个CATransaction中,如下所示。

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


13  

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.

正如Paulw11在他的评论中提到的,您可以使用animationDidStop:在文档中提到的方法。但是,您应该向您的CABasicAnimation/CAAnimation对象添加一个键,使您的animationDidStop:方法知道哪个对象已经完成。

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

在shake方法中添加一个值-key对来识别动画并将委托设置为self,例如:

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:

然后添加animationDidStop: delegate方法来通知您动画何时完成,以便您可以开始执行代码:

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
        }
    }
}

#1


54  

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

您可以使用CATransaction在动画完成后调用完成块。

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.

或者您也可以将这两个动画合并到一个CATransaction中,如下所示。

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


13  

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.

正如Paulw11在他的评论中提到的,您可以使用animationDidStop:在文档中提到的方法。但是,您应该向您的CABasicAnimation/CAAnimation对象添加一个键,使您的animationDidStop:方法知道哪个对象已经完成。

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

在shake方法中添加一个值-key对来识别动画并将委托设置为self,例如:

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:

然后添加animationDidStop: delegate方法来通知您动画何时完成,以便您可以开始执行代码:

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
        }
    }
}