Search code examples
swiftcashapelayercgpath

Animate CAShapeLayer's path by transform.scale property


I'm trying to animate scale of CAShapeLayer that has a circle path (playground compatible):

import UIKit
import PlaygroundSupport

let view = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 200)))
view.backgroundColor = .white

let animation = CABasicAnimation(keyPath: "transform.scale")
animation.duration = 1
animation.fromValue = 0
animation.toValue = 1
animation.autoreverses = true
animation.repeatCount = .greatestFiniteMagnitude

let frame = CGRect(origin: CGPoint(x: 40, y: 40), size: CGSize(width: 30, height: 30))
let path = CGPath(ellipseIn: frame, transform: nil)

let layer = CAShapeLayer()
layer.frame = frame
layer.path = path
layer.backgroundColor = UIColor.blue.cgColor
layer.fillColor = UIColor.red.cgColor

view.layer.addSublayer(layer)
layer.add(animation, forKey: nil)

PlaygroundPage.current.liveView = view

Here is the result:

enter image description here

The red circle is the figure that i trying to get animated with scale animation right in the center of its position and without any translation. This circle set as CGPath to CAShapeLayer.

The problem is obvious – my CAShapeLayer with blue background color animating as it expected, but the path – not.

Am i missed something or this is the way it works? Maybe this animation should be done in a different way?


Solution

  • If my understanding is correct, what you need is a bounds not frame.

    let frame = CGRect(origin: CGPoint(x: 40, y: 40), size: CGSize(width: 30, height: 30))
    

    should be:

    let bounds = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: 30, height: 30))
    let path = CGPath(ellipseIn: bounds, transform: nil)
    

    Hope it is what you need.