How to identify CAAnimation within the animationDidStop delegate?

Batgar picture Batgar · Aug 10, 2009 · Viewed 50.8k times · Source

I had a problem where I had a series of overlapping CATransition / CAAnimation sequences, all of which I needed to perform custom operations when the animations stopped, but I only wanted one delegate handler for animationDidStop.

However, I had a problem, there didn't appear to be a way to uniquely identify each CATransition / CAAnimation in the animationDidStop delegate.

I solved this problem via the key / value system exposed as part of CAAnimation.

When you start your animation use the setValue method on the CATransition / CAAnimation to set your identifiers and values to use when animationDidStop fires:

-(void)volumeControlFadeToOrange
{   
    CATransition* volumeControlAnimation = [CATransition animation];
    [volumeControlAnimation setType:kCATransitionFade];
    [volumeControlAnimation setSubtype:kCATransitionFromTop];
    [volumeControlAnimation setDelegate:self];
    [volumeControlLevel setBackgroundImage:[UIImage imageNamed:@"SpecialVolume1.png"] forState:UIControlStateNormal];
    volumeControlLevel.enabled = true;
    [volumeControlAnimation setDuration:0.7];
    [volumeControlAnimation setValue:@"Special1" forKey:@"MyAnimationType"];
    [[volumeControlLevel layer] addAnimation:volumeControlAnimation forKey:nil];    
}

- (void)throbUp
{
    doThrobUp = true;

    CATransition *animation = [CATransition animation]; 
    [animation setType:kCATransitionFade];
    [animation setSubtype:kCATransitionFromTop];
    [animation setDelegate:self];
    [hearingAidHalo setBackgroundImage:[UIImage imageNamed:@"m13_grayglow.png"] forState:UIControlStateNormal];
    [animation setDuration:2.0];
    [animation setValue:@"Throb" forKey:@"MyAnimationType"];
    [[hearingAidHalo layer] addAnimation:animation forKey:nil];
}

In your animationDidStop delegate:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{

    NSString* value = [theAnimation valueForKey:@"MyAnimationType"];
    if ([value isEqualToString:@"Throb"])
    {
       //... Your code here ...
       return;
    }


    if ([value isEqualToString:@"Special1"])
    {
       //... Your code here ...
       return;
    }

    //Add any future keyed animation operations when the animations are stopped.
 }

The other aspect of this is that it allows you to keep state in the key value pairing system instead of having to store it in your delegate class. The less code, the better.

Be sure to check out the Apple Reference on Key Value Pair Coding.

Are there better techniques for CAAnimation / CATransition identification in the animationDidStop delegate?

Thanks, --Batgar

Answer

vocaro picture vocaro · Sep 7, 2009

Batgar's technique is too complicated. Why not take advantage of the forKey parameter in addAnimation? It was intended for this very purpose. Just take out the call to setValue and move the key string to the addAnimation call. For example:

[[hearingAidHalo layer] addAnimation:animation forKey:@"Throb"];

Then, in your animationDidStop callback, you can do something like:

if (theAnimation == [[hearingAidHalo layer] animationForKey:@"Throb"]) ...