Reputation: 205
I am trying to animate a CAShapeLayer
along a UIBezierPath
. This works fine in circular path situations, but not when I use an oval path. The animation does happen, but pauses for a short period every time it has made a round, without me setting a delay.
Changing the size and time doesn't seem to improve on the issue, but makes the pause longer / shorter. For example, setting the duration to 1 in the animation below, the pause gets very short (in line with the speeding up of the rotation along the path).
This is the path:
let ovalPath = UIBezierPath(ovalIn: CGRect(x: -25, y: -50, width: 50, height: 100))
ovalPath.apply(CGAffineTransform(rotationAngle: 45 * .pi / 180))
ovalPath.apply(CGAffineTransform(translationX: frame.size.width / 2, y: frame.size.height / 2))
with it's ShapeLayer:
let ovalLayer = CAShapeLayer()
ovalLayer.strokeColor = UIColor.lightGray.cgColor
ovalLayer.fillColor = UIColor.clear.cgColor
ovalLayer.path = ovalPath.cgPath
view.layer.addSublayer(ovalLayer)
That shows the oval path, tilted 45 degrees. This is how I set the animation:
let animation = CAKeyframeAnimation(keyPath: #keyPath(CALayer.position))
animation.duration = 5
animation.repeatCount = MAXFLOAT
animation.path = ovalPath.cgPath
And finally the shape following the path:
let objectPath = UIBezierPath(arcCenter: CGPoint(x: 0 ,y: 0), radius: 50, startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
let objectLayer = CAShapeLayer()
objectLayer.path = objectPath.cgPath
objectLayer.strokeColor = UIColor.darkGray.cgColor
objectLayer.fillColor = UIColor.darkGray.cgColor
view.layer.addSublayer(objectLayer)
objectLayer.add(animation, forKey: nil)
I expect it to loop infinitely without pausing (which works exactly so in circular paths). Am I missing something obvious?
EDIT: tried using the timingFunction
as follows:
animation.timingFunction = CAMediaTimingFunction(name: <CAMediaTimingFunctionName>)
for example:
animation.timingFunction = CAMediaTimingFunction(name: .default)
EDIT 2:
This is what it currently looks like. The animation starts in the bottom right. Code for both ovals is exactly the same, except for the animation duration (1 vs 5 sec)
Upvotes: 4
Views: 840
Reputation: 257543
Here is a solution (jump is just gif animation end). Tested with Xcode 11.4 / iOS 13.4
let animation = CAKeyframeAnimation(keyPath: #keyPath(CALayer.position))
animation.duration = 5
animation.repeatCount = .greatestFiniteMagnitude // just recommended by Apple
animation.path = ovalPath.cgPath
animation.calculationMode = .paced // << required !!
Upvotes: 3