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. } }