Swift CAKeyframeAnimation & counting sheep

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

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.