开发者

CABasicAnimation rotate returns to original position

开发者 https://www.devze.com 2023-04-11 03:30 出处:网络
i\'m rotating a CALayer using CABasicAnimation and works fine. The problem is, when I try to rotate the same layer, it returns back to its original position before it will rotate. My expected output i

i'm rotating a CALayer using CABasicAnimation and works fine. The problem is, when I try to rotate the same layer, it returns back to its original position before it will rotate. My expected output is that, for the next rotation, it should start from where it has ended. Here's my code:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
animation.fromValue         = 0;
animation.toValue           = [NSNumber numberWithFloat:3.0];
animation.duration          = 3.0;
animation.timingFunction    = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseO开发者_开发技巧ut];
animation.removedOnCompletion = NO;
animation.fillMode          = kCAFillModeForwards;
animation.autoreverses      = NO;
[calayer addAnimation:animation forKey:@"rotate"];

Is there anything missing on my code? thanks


What's happening is that you're seeing the animation in the presentation layer. However, that doesn't update the actual position of your layer. So, once the animation finishes, you see the layer as it was because it hasn't changed.

It's really worth reading the "Core Animation Rendering Architecture". Otherwise this can be very confusing.

To fix it, set a delegate to your CABasicAnimation as follows:

[animation setDelegate:self];

Then, create a method to set your target properties that you want when the animation completes. Now, here's the confusing part. You should do this on animationDidStart not animationDidStop. Otherwise, the presentation layer animation will finish, and you'll get a flicker as you see the calayer in the original position then it jumps - without animation - to the target position. Try it with animationDidStop and you'll see what I mean.

I hope that's not too confusing!

- (void)animationDidStart:(CAAnimation *)theAnimation
{
    [calayer setWhateverPropertiesExpected];
}

EDIT:

I later discovered that Apple recommend a much better way to do this.

Oleg Begemann has a nice description of the correct technique in his blog post Prevent Layers from Snapping Back to Original Values When Using Explicit CAAnimations

Basically what you do is before you start the animation, you take a note of the layer's current value, i.e., the original value:

// Save the original value
CGFloat originalY = layer.position.y;

Next, set the toValue on the layer's model. Therefore the layer model has the final value of whatever animation you are about to do:

// Change the model value
layer.position = CGPointMake(layer.position.x, 300.0);

Then, you set the animation up with the animation fromValue being that original value that you noted above:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.y"];

// Now specify the fromValue for the animation because
// the current model value is already the correct toValue
animation.fromValue = @(originalY);
animation.duration = 1.0;

// Use the name of the animated property as key
// to override the implicit animation
[layer addAnimation:animation forKey:@"position"];

Note that code in edit above was copy/pasted from Ole Begemann's blog for clarity


If you want the animation to start from where it has ended, then set the fromValue property to the CALayer's current rotation.

Obtaining that value is tricky, but this SO post shows you how: https://stackoverflow.com/a/6706604/1072846

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号