Search code examples
iosswiftuikituibezierpathcabasicanimation

Create rotation animation for UIBezierPath


I have a CAShapeLayer that is a circle centered in the middle of the main View of my View Controller.

It looks like this:

CAShapeLayer (Circle)

The Problem I have is, that if I try to animate a rotation with the following code, it does not rotate around the center of the circle but somewhere else.

import UIKit

extension UIView {
    func addCircle(centerOfCircle: CGPoint, radius: CGFloat, startAngle: CGFloat?, endAngle: CGFloat?) {
        let circlePath = UIBezierPath(arcCenter: centerOfCircle, radius: radius, startAngle: startAngle ?? 0, endAngle: endAngle ?? CGFloat(Double.pi * 2), clockwise: true)

        let shapeLayer = CAShapeLayer()
        shapeLayer.path = circlePath.cgPath

        //change the fill color
        shapeLayer.fillColor = UIColor.clear.cgColor
        //you can change the stroke color
        shapeLayer.strokeColor = UIColor.red.cgColor

        shapeLayer.lineDashPattern = [1, 10]
        shapeLayer.lineCap = .round
        //you can change the line width
        shapeLayer.lineWidth = 3.0

        shapeLayer.anchorPoint = centerOfCircle

        let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
        rotation.toValue = NSNumber(value: Double.pi * 2)
        rotation.duration = 2
        rotation.isCumulative = true
        rotation.repeatCount = Float.greatestFiniteMagnitude



        shapeLayer.add(rotation, forKey: "rotationAnimation")

        self.layer.addSublayer(shapeLayer)
    }
}

What I get then is the following:

This is what it looks like

Any help would be highly appreciated!


Solution

  • Instead of animating the rotation, animate lineDashPhase property of the CAShapeLayer

    extension UIView {
        func addDashedCircle() {
            let circleLayer = CAShapeLayer()
            circleLayer.path = UIBezierPath(arcCenter: CGPoint(x: frame.size.width/2, y: frame.size.height/2),
                                            radius: frame.size.width/2,
                                            startAngle: 0,
                                            endAngle: .pi * 2,
                                            clockwise: true).cgPath
            circleLayer.lineWidth = 3.0
            circleLayer.strokeColor =  UIColor.red.cgColor
            circleLayer.fillColor = UIColor.white.cgColor
            circleLayer.lineJoin = .round
            circleLayer.lineDashPattern = [1,10]
    
            let animation = CABasicAnimation(keyPath: "lineDashPhase")
            animation.fromValue = 0
            animation.toValue = -11//1+10
            animation.duration = 1
            animation.repeatCount = .infinity
            circleLayer.add(animation, forKey: "line")
    
            layer.addSublayer(circleLayer)
        }
    }
    

    enter image description here