3
votes

I'm writing a toy app to experiment with some Core Animation features, including animating along a path (that's where the Sun's movement comes in) and manipulating time.

https://github.com/boredzo/WatchCompass

Animated screenshot of the app, showing the sun and the clock's hour hand going around.

(Never mind the button, which isn't implemented yet.)

The sun and watch face are CALayers, each containing a static image. The hour hand is a CAShapeLayer within the watch face layer, with its anchor point set to one end ((NSPoint){ 0.5, 1.0 }).

The sun is animated using a CAKeyframeAnimation along a path. The ellipse shows the path; you can see that they're not lined up for some reason, but that's a different question.

The hour hand's transform.rotation.z is animated using a CABasicAnimation, as described in this answer.

The problem—at least the one I'm asking about in this question—is the difference in duration.

Both animations are set to exactly the same duration, but the sun arrives back at its starting position a full two clock-hours before the hour hand does.

Of course, eventually the clock's duration will be exactly half the sun's duration (or its speed set to 2), since a clock only has 12 hours. If I do that, then the hour hand falls 4 clock-hours behind the sun, rather than 2.

Screenshot of the clock going around twice per virtual day and arriving four clock-hours late.

So, given that both animations have the same duration, or the duration of the clock's animation is an even multiple of the sun's animation, why does the clock take longer?

For that matter, although I'm not complaining, why does the sun wait for the clock to catch up?

1
No idea about that - generic suggestion: have you checked if sun's path have several last segments computed wrong for some reason and having 0 length (all in the same point)?Alexei Levenkov
@AlexeiLevenkov: I have not. The path is simply created with CGPathCreateWithEllipseInRect, so I would be surprised if it has more than two anchor points.Peter Hosey
I see. Rob Rix suggestion sounds right to me (As it is the second way to have wrong timing on last segments)...Alexei Levenkov
@AlexeiLevenkov: All the same, thanks for the suggestion, as the code I wrote to log those values (which I ended up not posting because Rob had posted his answer by then) helped me figure out the other problem.Peter Hosey
@PeterHosey Hi, the other problem meaning the one that has to deal with the CGPath not displaying correctly as the animation path in CAKeyedFrameAnimation? What causes that? I recently noticed the same in my animation, too. Thanks.Unheilig

1 Answers

7
votes

This appears to be due to the fact that you aren’t specifying a value for the keyTimes property of the keyframe animation. Per the documentation:

For the best results, the number of elements in the array should match the number of elements in the values property or the number of control points in the path property. If they do not, the timing of your animation might not be what you expect.

Indeed, setting keyTimes to @[ @0, @0.25, @0.5, @0.75, @1 ] appears to correct this.