Episode #151 | 19 minutes | published on January 8, 2015
Subscribers Only
In this episode we take a look at CoreAnimation's easiest form of animation with CABasicAnimation. Using this class we can animate properties of a layer, such as frame, background color, paths for CAShapeLayer, and more. We also cover timing functions and how to make a transition between shapes a bit easier for the system to interpolate between.

Episode Links

Creating the Layer

lazy var layer: CAShapeLayer = {
        let layer = CAShapeLayer()
        layer.path = UIBezierPath(rect: CGRectMake(0, 0, 100, 100)).CGPath
        layer.frame = CGRectMake(0, 0, 100, 100)
        layer.position =
        layer.fillColor = UIColor.redColor().CGColor
        return layer

Animating the position of the layer

        let posAnim = CABasicAnimation(keyPath: "position.x")
        posAnim.fromValue = layer.bounds.size.width / 2
        posAnim.toValue = view.frame.size.width - layer.bounds.size.width / 2
        posAnim.duration = anim.duration
        posAnim.repeatCount = 3
        posAnim.autoreverses = true
        posAnim.delegate = self
        posAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        layer.addAnimation(posAnim, forKey: "position")

Animating the fillColor of the layer

        let anim = CABasicAnimation(keyPath: "fillColor")
        anim.fromValue = UIColor.darkGrayColor().CGColor
        anim.toValue = UIColor.purpleColor().CGColor
        anim.repeatCount = 10
        anim.duration = 1.5
        anim.autoreverses = true
        layer.addAnimation(anim, forKey: "colorAnimation")

        layer.fillColor = anim.fromValue as CGColorRef

Animating the Path of the layer

        let pathAnim = CABasicAnimation(keyPath: "path")
        pathAnim.fromValue = layer.path
        pathAnim.toValue = trianglePath()
        pathAnim.duration = 4
        pathAnim.autoreverses = true
        pathAnim.repeatCount = HUGE
        layer.addAnimation(pathAnim, forKey: "pathAnimation")

The trianglePath method is defined as:

    func trianglePath() -> CGPathRef {
        let path = UIBezierPath()
        let w = layer.bounds.size.width
        let h = layer.bounds.size.height
        path.moveToPoint(CGPointMake(w/2, 0))
        path.addLineToPoint(CGPointMake(w/2, 0))
        path.addLineToPoint(CGPointMake(w, h))
        path.addLineToPoint(CGPointMake(0, h))
        return path.CGPath

Note the extra vertex here. This is useful to help guide the animation interpolator into animating properly between the triangle and square. Without it, the shape morphs in unnatural ways. For best results, always animate with the same number of vertices.

Getting the actual values of the layer

If you query for the fillColor, position or path during an animation, you’ll only see the value that the property contains. To get the actual values that you see on screen you need to query for the presentationLayer:

    func tick() {
        println("x: \(layer.presentationLayer()?.position.x)")

This might be nil if no animations are running, and if an animation is improperly configured then this may cause an EXC_BAD_ACCESS error.

blog comments powered by Disqus