views:

196

answers:

1

I'm having an intermittent problem when I move a UIImageView around the screen using CAKeyframeAnimation. I want the position of the UIImageView to remain where the animation ends when it is done. This bug only happens for certain start and end points. When I use random points it works correctly most of the time, but about 5-15% of the time it fails and snaps back to the pre-animation position. The problem only appears when using CAKeyframeAnimation using the path property. If I use the values property the bug does not appear. I am setting removedOnCompletion = NO, and fillMode = kCAFillModeForwards. I have posted a link to a test Xcode below. Here is my code for setting up the animation. I have a property usePath. When this is YES, the bug appears. When I set usePath to NO, the snap back bug does not happen. In this case I am using a path that is a simple line, but once I resolve this bug with a simple path, I will use a more complex path with curves in it.

// create the point        
CAKeyframeAnimation *moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
if (self.usePath) {
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, startPt.x, startPt.y);
    CGPathAddLineToPoint(path, NULL, endPt.x, endPt.y);
    moveAnimation.path = path;
    CGPathRelease(path);    
} else {
    moveAnimation.values = [NSArray arrayWithObjects:
                            [NSValue valueWithCGPoint:startPt],
                            [NSValue valueWithCGPoint:endPt],
                            nil];
}
moveAnimation.calculationMode = kCAAnimationPaced;
moveAnimation.duration = 0.5f;
moveAnimation.removedOnCompletion = NO;
// leaves presentation layer in final state; preventing snap-back to original state
moveAnimation.fillMode = kCAFillModeForwards; 
moveAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
// moveAnimation.delegate = self;    

// start the animation
[ball.layer addAnimation:moveAnimation forKey:@"moveAnimation"];

To dl and view my test project goto test project (http://www.24x7digital.com/downloads/PathFillModeBug.zip)

Tap the 'Move Ball' button to start the animation of the ball. I have hard coded a start and end point which causes the bug to happen every time. Use the switch to change usePath to YES or NO. When usePath is YES, you will see the snap back bug. When usePath is NO, you will not see the snap back bug.

I'm using SDK 3.1.3, but I have seen this bug using SDK 3.0 as well, and I have seen the bug on the Sim and on my iPhone.

Any idea on how to fix this or if I am doing something wrong are appreciated. Thanks, Mark.

+2  A: 

After contacting [email protected], they confirmed that there is a bug in Core Animation with respect to kCAFillModeForwards with paths. They told me to file a bug report which I did (Problem ID: 7797921).

They did try to give me a workaround. They said to set the end pt position right after I start the animation. This will keep the position from snapping back when the bug occurs:

// start the animation
[ball.layer addAnimation:moveAnimation forKey:@"moveAnimation"];
ball.layer.position = endPt;

But in my actual app I set rotationMode = kCAAnimationRotateAuto so that the objects z rotation is updated to keep it tangent to the path. So when the snap back occurs, the rotationMode z rotation is lost. They told me to set the rotation explicitly in animationDidStop:finished: like so:

[ball.layer setValue:[NSNumber numberWithDouble:-M_PI/2.0] forKeyPath:@"transform.rotation.z"];

This does not completely solve the problem because sometimes I get a flicker of the snap back rotation, and then the correction rotation. I'm hoping that they fix the fillMode = kCAFillModeForwards with paths bug.

Mark24x7