Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: consecutive CABasicAnimations that repeat

Goal:

  • First animation runs for a duration of 1.0
  • At 1.0, the second animation runs (while the first animation autoreverses back to its starting point)
  • At 2.0, the first animation is back at its starting point, the second animation has completed, and the first animation repeats
  • At 3.0, the second animation runs as the first animation concludes its second run

My code:

let animation = CABasicAnimation(keyPath: "transform.scale")
        animation.fromValue = 1.0
        animation.toValue = 1.5
        animation.duration = 1.0
        animation.autoreverses = true
        animation.repeatCount = .greatestFiniteMagnitude
        image1.layer.add(animation, forKey: animation.keyPath)

        let animation2 = CABasicAnimation(keyPath: "transform.scale")
        animation2.fromValue = 1.0
        animation2.toValue = 2.0
        animation2.duration = 1.0
        animation2.fillMode = .forwards

        let animation2b = CABasicAnimation(keyPath: "opacity")
        animation2b.fromValue = 1.0
        animation2b.toValue = 0.0
        animation2b.duration = 1.0
        animation2b.fillMode = .forwards

        let animationGroup = CAAnimationGroup()
        animationGroup.animations = [animation2, animation2b]
        animationGroup.duration = 2.0
        animationGroup.beginTime = 1.0
        animationGroup.repeatCount = .greatestFiniteMagnitude
        image2.layer.add(animationGroup, forKey: "scaleAndFade")

The goal is to start the 2nd animation 1.0 after the 1st animation. And since the animation group has a duration of 2.0 while the animations within it have a duration of only 1.0, the animation would start at 1.0, end at 2.0, and then not repeat again until 3.0

The two animations sometimes match up, but not on every build. Is there a more surefire way of starting the second animation to begin exactly at the end of the initial animation's first completed animation? So that they'll be in sync from that point on. Thanks for any help!

like image 585
RanLearns Avatar asked Nov 26 '25 00:11

RanLearns


1 Answers

I’m a little unclear on what we’re trying to achieve, but my sense is that the idea is that we have two views with repeating animations that need to be coordinated. To demonstrate an example of how this might be done, I chose to make both animations be a scale-up followed by a scale-down:

enter image description here

The animated gif here comes to an end after a few repetitions, but in actual fact the repetition just goes on forever.

That was simply achieved as follows:

func step1() {
    UIView.animate(withDuration: 1, animations: {
        self.v1.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
        self.v2.transform = .identity
    }) { _ in
        DispatchQueue.main.async {
            self.step2()
        }
    }
}

func step2() {
    UIView.animate(withDuration: 1, animations: {
        self.v1.transform = .identity
        self.v2.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
    }) { _ in
        DispatchQueue.main.async {
            self.step1()
        }
    }
}

The point is that the stages of the animation can never get out of sync between the two views, because each stage involves both views and follows the previous stage. So I’m pretty sure you can adapt that approach to fit your animation.

like image 89
matt Avatar answered Nov 27 '25 13:11

matt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!