40

I am trying to create a falling coin. The coin image is a CALayer with 2 CABasicAnimations on it - a falling down and a rotation one. When the falling down animation gets to its end, it stays there. The rotation animation though, which is supposed to be random and end up in a different angle every time, just pops back to the original CALAyer image.

I want it to stay in the angle it finished the animation on. Is it possible? How do I do it?

Code:

//Moving down animation:
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
anim.duration = 1;
anim.autoreverses = NO;
anim.removedOnCompletion = YES;

anim.fromValue = [NSNumber numberWithInt: -80 - row_height * (8 - _col)];
anim.toValue = [NSNumber numberWithInt: 0];

//Rotation Animation:
CABasicAnimation *rota = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rota.duration = 4;
rota.autoreverses = NO;
rota.removedOnCompletion = NO;
rota.fromValue = [NSNumber numberWithFloat: 0];
rota.toValue = [NSNumber numberWithFloat: 2.5 * 3.15 ];
[cl addAnimation: rota forKey: @"rotation"];
[cl addAnimation: anim forKey: @"animateFalling"];
return true
  • 7,839
  • 2
  • 19
  • 35
Mikle
  • 1,842
  • 4
  • 20
  • 32

3 Answers3

79

Have you set the removedOnCompletion property of the rotation animation to NO, e.g.,

rota.removedOnCompletion = NO;

That should leave the presentation layer where it was when the animation finished. The default is YES, which will snap back to the model value, i.e., the behavior you describe.

The fillMode should also be set, i.e.,

rota.fillMode = kCAFillModeForwards;
Allan Bazinet
  • 1,752
  • 15
  • 15
  • 10
    the fillMode thing solved it. God knows why is that needed :) – Mikle Sep 04 '09 at 19:28
  • @Allan Any idea why `fillMode` needs to be set to `kCAFillModeForwards`? – pixelfreak Jul 26 '11 at 02:44
  • Are you sure it’s necessary to set `removedOnCompletion` to `NO`? When I tried something similar, setting `fillMode` to `kCAFillModeForwards` appeared to be sufficient. – al45tair Feb 07 '12 at 14:00
  • Setting the fillMode tells "The receiver remains visible in its final state when the animation is completed." according to the docs-thats why the fillMode needs to be sets to forward. – coder May 23 '12 at 18:24
  • 18
    9 times out of 10, this is the wrong answer. You need to actually set layer's property. Setting fillModeForwards and removedOnCompletion give the appearance of change, however, if you query the layer at the end of the animation, you'll see that its property is still set to the original value. That's rarely (if ever) what you want: http://stackoverflow.com/questions/3581804/uiimageview-is-disappearing-after-cakeyframeanimation/3586433#3586433 – Matt Long Apr 01 '13 at 17:31
  • 2
    I agree with @MattLong. Setting `removedOnCompletion` to `NO` is especially bad because it keeps the animation running in an idle state, forever doomed in an infinite loop. – zakdances Apr 26 '13 at 13:14
4

I was trying to rotate an arrow back and forth, like the Twitter/Facebook "Pull to Refresh" effect.

The problem is, I was doing the rotation back and forth on the same UIView, so after adding

rotation.removedOnCompletion = NO;
rotation.fillMode = kCAFillModeForwards;

The forward animation war working OK but the backwards animation was not working at all.

So I added the last line suggested by yeahdixon, and in addition set the view's transform to the animation's completed state: (rotation by 180 degrees)

[myview.layer removeAllAnimations];
myView.transform = CGAffineTransformMakeRotation(M_PI);

For the 'restore' animation (backwards) I do this on completion:

myView.transform = CGAffineTransformMakeRotation(0);

...and it works fine. Somehow it doesn't need the removeAllAnimations call.

Nicolas Miari
  • 16,006
  • 8
  • 81
  • 189
  • Digging back old answers, but +1 for the `removeAllAnimations` thing. That made my flickering stop. – Cyrille Feb 04 '13 at 17:14
1

I found that by setting : removedOnCompletion = NO;

did not produce a visible leak in instruments, but did not get deallocated and was accumulating a small amount of memory. IDK if its my implementation or what, but by adding removeAllAnimations at the end of the animation seemed to clear out this tiny bit of residual memory.

[myview.layer removeAllAnimations];
yeahdixon
  • 6,647
  • 1
  • 41
  • 43
  • Is it on simulator or device? – Pablo Nov 05 '10 at 00:58
  • yeah good point, it was on simulator, and I did not try on device, which obviously is the real deal. It was a very very small increase. BUt, I found this cause i was hunting for another leak using instruments and i was seeing strange memory behavior. Doing this isolated the true leak i had, and i was able to plug up the hole.note this is xcode 3.2.4 and after this, i did get memory to consistently return to its starting number- which feels good. – yeahdixon Nov 11 '10 at 16:02
  • 1
    You are animating the presentation layer. Then you should set the `transform` property of the model layer to the final value, but instead you preserve the presentation layer with `removedOnCompletion=NO`, thus, ending up with two layers instead one. That's why you see an increase of memory. – Jano Dec 13 '12 at 23:01