CAGroupAnimation does not show animations. Animations work fine when added separately

1.5k views Asked by At

I am implementing a simple activity indicator using Swift and Core Animation. The core animation loop consists of just two animations. When I add them to the layer directly, they work perfectly. When I add them as a CAAnimationGroup, nothing is happening at all. I am utterly confused by this behaviour, and I've already checked all questions on stackoverflow about CAAnimationGroup, all tutorials on the web, and read official docs many times. I can't figure out what's going on. Please help.

Animations:

let anim1 = CABasicAnimation(keyPath: "strokeEnd")
anim1.fromValue = 0
anim1.toValue = 1.0
anim1.duration = 2.0
anim1.beginTime = CACurrentMediaTime()

let anim2 = CABasicAnimation(keyPath:"strokeStart")
anim2.fromValue = 0
anim2.toValue = 1.0
anim2.duration = 2.0
anim2.beginTime = CACurrentMediaTime() + 2.0

This works perfectly as expected:

shapeLayer.addAnimation(anim1, forKey:nil)
shapeLayer.addAnimation(anim2, forKey:nil)

This does nothing whatsoever to my layer:

let group = CAAnimationGroup()
group.animations = [anim1, anim2]
group.duration = 4.0
shapeLayer.addAnimation(group, forKey: nil)

I made a short demo snippet to be used in Playground: https://gist.github.com/anonymous/6021295eab4e00b813ce. Please see for yourself and help me solve this. (In case you're not sure how to use Playground for prototyping animations: http://possiblemobile.com/2015/03/prototyping-uiview-animations-swift-playground/)

3

There are 3 answers

1
Duncan C On BEST ANSWER

@MDB983's answer looks like it would work, but doesn't explain why.

When you add an animation directly to a layer, it's begin time is based on the current media time.

When you add animations to an animation group, their "local time" is the animation group. A begin time of 0 in an animation group is the beginning of the group, and a beginTime of 1.0 is 1 second into the total animation group, etc. When you add animations to an animation group change your begin times to be zero-based, not starting from CACurrentMediaTime().

0
MDB983 On

Try it this way, seemingly CACurrentMediaTime() + 2.0 is causing an issue

import UIKit
import XCPlayground
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
let shapeLayer = CAShapeLayer()
let size:CGFloat = 52
let rect = CGRect(x: view.bounds.midX - size/2, y: view.bounds.midY-size/2, width: size, height: size)
shapeLayer.path = UIBezierPath(ovalInRect: rect).CGPath
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.lineWidth = 3
shapeLayer.strokeStart = 0
shapeLayer.strokeEnd = 0
view.layer.addSublayer(shapeLayer)
XCPShowView("view", view)

let beginTime = CACurrentMediaTime()
let anim1 = CABasicAnimation(keyPath: "strokeEnd")
anim1.fromValue = 0
anim1.toValue = 1
anim1.duration = 2

let anim2 = CABasicAnimation(keyPath:"strokeEnd")
anim2.fromValue = 1
anim2.toValue = 0
anim2.duration = 2
anim2.beginTime =  2

let group = CAAnimationGroup()
group.duration = 4.0
group.removedOnCompletion = true
group.animations = [anim1, anim2]
//shapeLayer.addAnimation(anim1, forKey:nil)
//shapeLayer.addAnimation(anim2, forKey:nil)
shapeLayer.addAnimation(group, forKey: nil)
0
Mike Diente On

I know this is an old question but I was doing the same with animation group in swift 4. What I missed is specifying the beginTime for the CAAnimationGroup itself (I assumed that the child animations would follow their beginTime). By default, beginTime is 0.0 for CAAnimationGroup

let group = CAAnimationGroup()
group.beginTime = CACurrentMediaTime() + delay
group.duration = 4.0
group.removedOnCompletion = true
group.animations = [anim1, anim2]