Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sequence two animations with delay in between

I have a UIImageView which i want to rotate 180 degrees, taking up 1 second, then i want to wait 1 second at this position, then rotate 180 degrees back to the original position taking up 1 second.

How do i accomplish this? I've tried a 100 approaches and it keeps snapping back instead of rotating back

EDIT: I forgot to add i need this to repeat indefinitely

like image 819
mikkelam Avatar asked Sep 03 '17 08:09

mikkelam


People also ask

How do I make two animations happen at the same time in Powerpoint?

On the Animations tab, click Animation Pane. Click Add Animation, and pick an animation effect. To apply additional animation effects to the same object, select it, click Add Animation and pick another animation effect.

How do you add an animation-delay in CSS?

The CSS animation-delay property has the following syntax: animation-delay: [time] | initial | inherit; As you can see, there are three possible values: time, initial, and inherit. The first option is [time], which is the number of seconds or milliseconds before the animation starts.

What is animation duration?

The time that an animation takes to complete one cycle. This may be specified in either seconds ( s ) or milliseconds ( ms ).


2 Answers

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:

enter image description here

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()
        }
    }
}
like image 190
dirtydanee Avatar answered Oct 12 '22 14:10

dirtydanee


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()
        })
    }
}
like image 31
Giuseppe Sapienza Avatar answered Oct 12 '22 13:10

Giuseppe Sapienza