How to sequence two animations with delay in between

浪子不回头ぞ 提交于 2019-12-01 07:15:39

You can perform the second animation in the completionHandler presented on UIView.animate

let duration = self.transitionDuration(using: transitionContext)

let firstAnimDuration = 0.5
UIView.animate(withDuration: firstAnimDuration, animations: {
    /* Do here the first animation */
}) { (completed) in

   let secondAnimDuration = 0.5
   UIView.animate(withDuration: secondAnimDuration, animations: { 
       /* Do here the second animation */
   })
}

Now you could have another problem.

If you rotate your view with the CGAffineTransform and for every animation you assign a new object of this type to your view.transform, you will lose the previous transform operation

So, according to this post: How to apply multiple transforms in Swift, you need to concat the transform operation

Example with 2 animation block

This is an example to made a rotation of 180 and returning back to origin after 1 sec:

let view = UIView.init(frame: CGRect.init(origin: self.view.center, size: CGSize.init(width: 100, height: 100)))
view.backgroundColor = UIColor.red
self.view.addSubview(view)

var transform = view.transform
transform = transform.rotated(by: 180)

UIView.animate(withDuration: 2, animations: {
    view.transform = transform
}) { (completed) in

    transform = CGAffineTransform.identity
    UIView.animate(withDuration: 2, delay: 1, options: [], animations: { 
        view.transform = transform
    }, completion: nil)
}

Example of .repeat animation and .autoreverse

The .animate method give you the ability to set some animation options. In particular the structure UIViewAnimationOptions contains:

  1. .repeat, which repeat indefinitely your animation block
  2. .autoreverse, which restore your view to the original status

With this in mind you could do this:

var transform = view.transform.rotated(by: 180)
UIView.animate(withDuration: 2, delay: 0, options: [.repeat, .autoreverse], animations: {
     self.myView.transform = transform
})

But you need a delay between the two animations, so you need to do this trick:

Example of recursive animation and a delay of 1 sec

Just create a method inside your ViewController which animate your view. In the last completionHandler, just call the method to create a infinite loop.

Last you need to call the method on viewDidAppear to start the animation.

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    self.animation()
}


func animation() {
    var transform = view.transform
    transform = transform.rotated(by: 180)

    UIView.animate(withDuration: 2, delay: 0, options: [], animations: {

        self.myView.transform = transform

    }) { bool in
        transform = CGAffineTransform.identity

        UIView.animate(withDuration: 2, delay: 1, options: [], animations: {

            self.myView.transform = transform

        }, completion: { bool in
            self.animation()
        })
    }
}

All you need to do is to create a keyFrame animations. It is designed to chain multiple animations together, and in the first keyframe rotate your UIImageView subclass by PI, and in the second one transform it back to identity.

        let rotateForwardAnimationDuration: TimeInterval = 1
        let rotateBackAnimationDuration: TimeInterval = 1
        let animationDuration: TimeInterval = rotateForwardAnimationDuration + rotateBackAnimationDuration

        UIView.animateKeyframes(withDuration: animationDuration, delay: 0, options: [], animations: { 
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: rotateForwardAnimationDuration) {
                self.imageView.transform = CGAffineTransform(rotationAngle: .pi)
            }

            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: rotateBackAnimationDuration) { 
                self.imageView.transform = .identity 
            }
        })

Outcome:

EDIT: Here is an example how to make it run indefinitely. I suppose your image is in a viewController, and you hold some reference to your imageView.

So for example, on viewDidAppear, call a function what triggers the animation, and than in the completion block of the animation, just call the same function again.

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.runRotateAnimation()
    }

    func runRotateAnimation() {
        let rotateForwardAnimationDuration: TimeInterval = 1
        let rotateBackAnimationDuration: TimeInterval = 1
        let animationDuration: TimeInterval = rotateForwardAnimationDuration + rotateBackAnimationDuration

        UIView.animateKeyframes(withDuration: animationDuration, delay: 0, options: [], animations: { 
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: rotateForwardAnimationDuration) {
                self.imageView.transform = CGAffineTransform(rotationAngle: .pi)
            }

            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: rotateBackAnimationDuration) { 
                self.imageView.transform = .identity 
            }
        }) { (isFinished) in
            // To loop it continuosly, just call the same function from the completion block of the keyframe animation
            self.runRotateAnimation()
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!