10
votes

How can I have one CABasicAnimation to run after the other one has finishes? In other words sequentially. I've added the begin time of the second animation, however it seems that the second animation doesn't gets executed:

CABasicAnimation * appearance =[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    appearance.duration = 0.5;
    appearance.fromValue = [NSNumber numberWithFloat:0];
    appearance.toValue = [NSNumber numberWithFloat:340];
    appearance.repeatCount = 1;
    appearance.fillMode = kCAFillModeForwards;
    appearance.removedOnCompletion = NO;
    [notif.layer addAnimation:appearance forKey:@"transform.translation.y"];



    CABasicAnimation * theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    theAnimation.duration = 0.5;
    theAnimation.fromValue = [NSNumber numberWithFloat:0];
    theAnimation.toValue = [NSNumber numberWithFloat:10];
    theAnimation.repeatCount = 3;
    theAnimation.autoreverses = YES;
    theAnimation.fillMode = kCAFillModeForwards;
    theAnimation.removedOnCompletion = NO;
    theAnimation.beginTime = appearance.beginTime + appearance.duration;
    [notif.layer addAnimation:theAnimation forKey:@"transform.translation.y"];

Any idea why?

4

4 Answers

15
votes

Updated Code, this will work!

1st animation

CABasicAnimation * appearance =[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    [appearance setValue:@"animation1" forKey:@"id"];
    appearance.delegate = self;
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:)];
    appearance.duration = 0.5;
    appearance.fromValue = [NSNumber numberWithFloat:0];
    appearance.toValue = [NSNumber numberWithFloat:340];
    appearance.repeatCount = 1;
    appearance.fillMode = kCAFillModeForwards;
    appearance.removedOnCompletion = NO;
    [notif.layer addAnimation:appearance forKey:@"transform.translation.y"];

2nd Animation:

    - (void)animationDidStop:(CAAnimation *)theAnimation2 finished:(BOOL)flag {
    if([[theAnimation2 valueForKey:@"id"] isEqual:@"animation1"]) {
    CABasicAnimation * theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    theAnimation.duration = 0.5;
    theAnimation.fromValue = [NSNumber numberWithFloat:0];
    theAnimation.toValue = [NSNumber numberWithFloat:10];
    theAnimation.repeatCount = 3;
    theAnimation.autoreverses = YES;
    theAnimation.fillMode = kCAFillModeForwards;
    theAnimation.removedOnCompletion = NO;
    theAnimation.beginTime = appearance.beginTime + appearance.duration;
    [notif.layer addAnimation:theAnimation forKey:@"transform.translation.y"];
}

}

This is how the 2nd animation would fire after the 1st one finishes.

1
votes

The simplest thing to do is set up a delegate for the first animation and in that object implement -animationDidStop:finished:. In that method, touch off the second animation.

1
votes

The reason your animation in not running according to plan is due to the way you have coded up & used Core Animation. Core animations are all GPU powered. CA infact handles couple of things very well to render animations optimally.

One element of it is the raw parallel processing power of modern graphics cards, and another is the fact that Core Animation can cache the contents of a CALayer on the card so that your code doesn't need to constantly redraw it. This, by the way, is part of the reason the iPhone UI is so incredibly fast on some relatively modest hardware. Core Animation can automatically take advantage of a multi-core Mac because the layer tree is rendered on a separate thread.

The last line is imp. CA's are running in a separate thread ( & not the main thread). So coming back to your problem, you have 2 blocks of CA's each trying to animate same transform.translation.y Both at the same time! How would this work?

So to solve this, either do -

  1. What someone suggested, put a delay for the second animation so that after the first animates, second kicks in only after the first os over.
  2. or Try to do the entire animation in one single block (again as someone suggested).

I just wanted to highlight the theory & reasoning behind the way Core Animation works. Hope this helps...

-1
votes

The easiest and cleanest way is to use a CAAnimationGroup. Take a look at this answer - it helped me out.

Chaining Core Animation animations