4
votes

I have a UIView whose layer has 2 sublayers, one is a CAShapeLayer, and the other a CALayer.

The CAShapeLayer has a path set using bezierPathWithOvalInRect, and is animated using CABasicAnimation. The "strokeEnd" property is animated from 0.0 to 1.0, over a certain duration. This has the effect of seeing the oval draw from beginning to end over the duration.

The CALayer simply has its contents set to a pencil image, and is animated using CAKeyframeAnimation. The "position" property is animated by setting the path property of the CAKeyframeAnimation to the same path as the CAShapeLayer, and the same duration as the CABasicAnimation. This has the effect of the pencil moving along the same path during the same duration, and it looks like the pencil is drawing the oval.

Works beautifully in iOS6. However, in iOS7, the timing is off - the position and strokeEnd animations are not in sync - they are in sync at specific moments, specifically at times 0, duration/4, duration/2, duration*3/4, and duration - but in between, the synchronization is off.

If instead of an ellipse, I use a rectangle or triangle, for example, it works great in iOS6 and iOS7. Only issue is an ellipse in iOS7.

Essentially I need to know how to synchronize 2 different animations, where each animation is animating a different layer.

Here is the code that creates the 2 layers:

self.drawingLayer = [CAShapeLayer layer];
self.drawingLayer.frame = self.view.bounds;
self.drawingLayer.bounds = drawingRect;
self.drawingLayer.path = path.CGPath;
self.drawingLayer.strokeColor = [[UIColor blackColor] CGColor];
self.drawingLayer.fillColor = nil;
self.drawingLayer.lineWidth = 10.0f;
self.drawingLayer.lineJoin = kCALineJoinRound;
self.drawingLayer.lineCap = kCALineJoinRound;

[self.view.layer addSublayer:self.drawingLayer];

UIImage *pencilImage = [UIImage imageNamed:@"pencil.png"];
self.pencilLayer = [CALayer layer];
self.pencilLayer.contents = (id)pencilImage.CGImage;
self.pencilLayer.contentsScale = [UIScreen mainScreen].scale;
self.pencilLayer.anchorPoint = CGPointMake(0.0, 1.0); //bottom left corner
self.pencilLayer.frame = CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);

[self.view.layer addSublayer:self.pencilLayer];

And here is the code that creates and starts the 2 different animations (self.drawingLayer is the CAShapeLayer, and self.pencilLayer is the CALayer)

CABasicAnimation *drawingAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
drawingAnimation.duration = 10.0;
drawingAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
drawingAnimation.toValue = [NSNumber numberWithFloat:1.0f];
[self.drawingLayer addAnimation:drawingAnimation forKey:@"strokeEnd"];

CAKeyframeAnimation *pencilAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
pencilAnimation.duration = drawingAnimation.duration;
pencilAnimation.path = self.drawingLayer.path;
pencilAnimation.calculationMode = kCAAnimationPaced;
pencilAnimation.delegate = self;
pencilAnimation.fillMode = kCAFillModeForwards;
pencilAnimation.removedOnCompletion = NO;
[self.pencilLayer addAnimation:pencilAnimation forKey:@"position"];

UPDATE

Here's a test app that illustrates the problem.

https://github.com/xjones/AnimatedPaths

2
Have you tried putting you animations in a CATransaction? Right now each one is taking place in its own implicit transaction preventing synchronization. developer.apple.com/library/ios/documentation/GraphicsImaging/…Brian Nickel♦
Yes, I tried the various class methods of CATransaction and they don't do anything to solve this problem...user2860400

2 Answers

5
votes

Apple has informed me this is a known bug in iOS7, and they asked me to file a bug as well, to help them understand the demand for a fix. The tech support person at Apple told me he does not know of a workaround. If any of you figure out a workaround, I’m all ears...

0
votes

I filed Apple bug reporter bug #15191834 on Oct 9, 2013. In my testing with iOS 8.1 and Xcode 6.1.1 the bug is still there in the Simulator and in the device. The bug was introduced in iOS 7 and has never been fixed.

Please file a bug so Apple can see others are impacted!