3
votes

I am trying to move a CALayer a few points every time a user does something. I setup the animation to run relatively slowly but when I set the position of the layer after setting up the animation the implicit animation seems to take over and perform the animation quickly. Here is basically what my code looks like:

    CGPoint point = CGPointMake(layer.position.x + 30, layer.position.y + 30);
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.fromValue = [NSValue valueWithCGPoint: layer.position];
    animation.toValue = [NSValue valueWithCGPoint: point];
    animation.duration = 4;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    [layer addAnimation:animation forKey:@"position"];
    layer.position = point;

I have tried removing the last layer.position = point line which results in the first animation running as expected, but then when I try to run the animation a second time the layer jumps back to where the layer was before I ran the first animation. Currently the only way I have been able to resolve this is by adding a delegate to the animation that implements animationDidStop and setting the layer's point after the animation is completed. But looking at a lot of other people's sample code this should not be required. Is there something I am doing wrong?

2
You are not repeatedly adding an animation to the same layer are you? I notice you have removedOnCompletion = NO and you don't show the code to remove the animation from the layer...trojanfoe
what is exactly layer? could you show how you initialize the layer variable? besides this: I suppose that if you use removedOnCompletion = YES, then the layer goes back to the initial position right after the animation completion, does it?sergio
@trojanfoe I am trying to repeat that same animation block multiple times without removing the animation from the layer. @sergio The layer is a CAShapeLayer which is just a a circle right now. If I use removedOnCompletion = YES or remove animation.fillMode = kCAFillModeForwards then the layer snaps back to its original position after the animation is complete. My goal is the progressively to move the layer every time the animation is run.Yanamon

2 Answers

0
votes

You should take a look at the WWDC'11 session 421 - Core Animation Essentials, on 45:21 there is an example similar of yours.

They first set the new value on the layer, create the animation then add it to the layer. One thing that you must notice is the fillMode property, it should be kCAFillModeBackwards.

0
votes

You don't need to mess with removedOnCompletion or fillMode. The incorrect position you're seeing is not due to implicit animation. The only thing you failed to do was to set the new position of the layer immediately before running the animation. Your problem was that you set the new position after adding the animation. Here's how a functional version would look in Swift 3:

let newPoint = CGPoint(x: layer.position.x + 30, y: layer.position.y + 30)

let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(cgPoint: layer.position)
animation.toValue = NSValue(cgPoint: newPoint)

layer.setValue(NSValue(cgPoint: newPoint), forKeyPath: "position")

layer.add(animation, forKey: nil)