Today I had the need to create a looping animation of a looping series of sheep – much as you’d imagine a child counting them. This is what I came up with tonight, after having about zero experience doing this kind of thing.
[KGVID width=”428″ height=”148″]http://blog.ericd.net/wp-content/uploads/2015/11/sheep.mov[/KGVID]
I performed a lot of trial and error here, and the delays for getting more sheep activated might not be the right approach… I didn’t see a way to delay animations any other way (yet).
Here is my entire code for this effect – I can explain when I have more time to actually walk through the code and explain what’s going on. I think it’s fairly self-explanatory and once you do this, it becomes easier to think about.
class ViewController: UIViewController {
var foo: UIImageView!
var bar: UIImageView!
var third: UIImageView!
var container: UIView!
var pathAnimation: CAKeyframeAnimation!
var pathAnimation2: CAKeyframeAnimation!
var scaleAnim: CAKeyframeAnimation!
var alphaAnim: CAKeyframeAnimation!
var group: CAAnimationGroup!
override func viewDidLoad() {
super.viewDidLoad()
container = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 100))
container.backgroundColor = UIColor.lightGrayColor()
self.view.addSubview(container)
foo = UIImageView(frame: CGRect(x: 70, y: 120, width: 60, height: 30))
foo.contentMode = .ScaleAspectFit
foo.image = UIImage(named: "sheep.png")
container.addSubview(foo)
bar = UIImageView(frame: CGRect(x: 70, y: 120, width: 60, height: 30))
bar.contentMode = .ScaleAspectFit
bar.image = UIImage(named: "sheep.png")
container.addSubview(bar)
third = UIImageView(frame: CGRect(x: 70, y: 120, width: 60, height: 30))
third.contentMode = .ScaleAspectFit
third.image = UIImage(named: "sheep.png")
container.addSubview(third)
let mask = CALayer()
mask.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 100)
mask.backgroundColor = UIColor.blackColor().CGColor
container.layer.mask = mask
container.layer.masksToBounds = true
//Moving along an arc.
pathAnimation = CAKeyframeAnimation(keyPath: "position")
pathAnimation.setValue("turnAnimation", forKey: "tag")
pathAnimation.rotationMode = kCAAnimationRotateAuto
pathAnimation.calculationMode = kCAAnimationPaced
let curvedPath = CGPathCreateMutable()
CGPathMoveToPoint(curvedPath, nil, 70, 120)
CGPathAddCurveToPoint(curvedPath, nil, 70, 120, 160, -10, 250, 120)
pathAnimation.path = curvedPath
//Scaling up and down.
scaleAnim = CAKeyframeAnimation(keyPath: "transform.scale")
scaleAnim.values = [0.6, 1.0, 0.6]
scaleAnim.duration = 10
//Adjust alpha
alphaAnim = CAKeyframeAnimation(keyPath: "opacity")
alphaAnim.values = [0.0, 1.0, 0.0]
alphaAnim.duration = 10
//Group them up.
group = CAAnimationGroup()
group.animations = [pathAnimation, scaleAnim, alphaAnim]
group.duration = 10.0
group.repeatCount = Float.infinity
group.removedOnCompletion = false
group.fillMode = kCAFillModeRemoved
foo.layer.addAnimation(group, forKey: "doit")
let delayInSeconds = 3.33;
let delay = delayInSeconds * Double(NSEC_PER_SEC)
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay));
dispatch_after(popTime, dispatch_get_main_queue(), {
self.bar.layer.addAnimation(self.group, forKey: "doit2")
});
let delayInSeconds3 = 6.4;
let delay3 = delayInSeconds3 * Double(NSEC_PER_SEC)
let popTime3 = dispatch_time(DISPATCH_TIME_NOW, Int64(delay3));
dispatch_after(popTime3, dispatch_get_main_queue(), {
self.third.layer.addAnimation(self.group, forKey: "doit3")
});
}
override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
print("done", anim.valueForKey("tag"))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}