105 votes

Comment identifier CAAnimation dans le animationDidStop délégué?

J'ai eu un problème où j'ai eu une série de chevauchement CATransition / CAAnimation séquences, toutes dont j'avais besoin pour effectuer des opérations personnalisées lorsque les animations arrêté, mais je voulais seulement un gestionnaire de délégués pour animationDidStop.

Cependant, j'ai eu un problème, il ne semble pas être un moyen d'identifier de manière unique chaque CATransition / CAAnimation dans le animationDidStop délégué.

J'ai résolu ce problème par le biais de la clé / système de valeurs exposées dans le cadre de CAAnimation.

Lorsque vous démarrez votre animation utiliser la méthode setValue sur le CATransition / CAAnimation pour définir vos identifiants et les valeurs à utiliser lors de la animationDidStop les incendies:

-(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];
}

Dans votre animationDidStop délégué:

- (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.
 }

L'autre aspect est qu'il vous permet de garder de l'état dans la valeur de la clé d'appariement système au lieu de le stocker dans votre délégué de classe. Le moins de code, mieux c'est.

Assurez-vous de vérifier la Pomme de Référence sur la Valeur de la Clé de la Paire de Codage.

Sont t-il de meilleures techniques pour CAAnimation / CATransition d'identification dans le animationDidStop délégué?

Merci, --Batgar

93voto

vocaro Points 1995

Batgar la technique est trop compliqué. Pourquoi ne pas profiter de la forKey paramètre dans addAnimation? Il a été prévu à cet effet. Il suffit de prendre l'appel à setValue et de déplacer la chaîne de clé à la addAnimation appel. Par exemple:

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

Puis, dans votre animationDidStop de rappel, vous pouvez faire quelque chose comme:

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

46voto

Duncan C Points 18661

Je suis juste venu avec une bien meilleure façon de faire de la complétion de code pour CAAnimations:

J'ai créé une définition de type d'un bloc:

typedef void (^animationCompletionBlock)(void);

Et une clé que j'utilise pour ajouter un bloc à une animation:

#define kAnimationCompletionBlock @"animationCompletionBlock"

Ensuite, si je veux lancer l'animation code d'achèvement après un CAAnimation finitions, j'ai mis moi-même en tant que délégué de l'animation, et d'ajouter un bloc de code à l'animation à l'aide setValue:forKey:

animationCompletionBlock theBlock = ^void(void)
{
  //Code to execute after the animation completes goes here    
};
[theAnimation setValue: theBlock forKey: kAnimationCompletionBlock];

Ensuite, je mets en œuvre une animationDidStop:fini: méthode, qui vérifie la présence d'un bloc à la clé spécifiée et l'exécute si trouvé:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
  animationCompletionBlock theBlock = [theAnimation valueForKey: kAnimationCompletionBlock];
  if (theBlock)
    theBlock();
}

La beauté de cette approche est que vous pouvez écrire le code de nettoyage dans le même endroit où vous créez l'objet d'animation. Mieux encore, depuis que le code est un bloc, il a accès aux variables locales dans le cadre englobant dans lequel elle est définie. Vous n'avez pas de gâchis avec la mise en place userInfo dictionnaires ou d'autres sottises, et ne pas avoir à écrire de plus en plus animationDidStop:fini: méthode qui devient de plus en plus complexe à mesure que vous ajoutez des différents types d'animations.

Pour dire la vérité, CAAnimation devrait avoir un achèvement propriété de bloc construit en elle, et le système de soutien pour appeler automatiquement si celle-ci est spécifiée. Toutefois, le code ci-dessus vous donne la même fonctionnalité avec seulement quelques lignes de code supplémentaire.

33voto

jimt Points 885

La deuxième approche ne fonctionnera que si vous définissez explicitement votre animation pour ne pas être supprimé à la fin avant de l'exécuter:

CAAnimation *anim = ...
anim.removedOnCompletion = NO;

Si vous ne le faites pas, votre animation sera supprimé avant lorsqu'elle est terminée, et le rappel de ne pas le trouver dans le dictionnaire.

31voto

Tibidabo Points 10510

Toutes les autres réponses sont trop compliqués! Pourquoi ne pas vous suffit d'ajouter votre propre touche d'identifier l'animation?

Cette solution est très facile il vous suffit d' ajouter votre propre clé de l'animation (animationID dans cet exemple)

Insérez cette ligne pour identifier animation1:

[myAnimation1 setValue:@"animation1" forKey:@"animationID"];

et ce afin d'identifier animation2:

[myAnimation2 setValue:@"animation2" forKey:@"animationID"];

Test comme ceci:

- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag
{
    if([[animation valueForKey:@"animationID"] isEqual:@"animation1"]) {
    //animation is animation1

    } else if([[animation valueForKey:@"animationID"] isEqual:@"animation2"]) {
    //animation is animation2

    } else {
    //something else
    }
}

Il ne nécessite pas de variables d'instance:

15voto

t0rst Points 194

Pour rendre explicite ce qui est implicite à partir de ci-dessus (et ce qui m'a amené ici après quelques gaspillée heures): ne vous attendez pas à voir l'animation d'origine de l'objet que vous avez alloué passé par

 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag 

lorsque l'animation est terminée, car [CALayer addAnimation:forKey:] fait une copie de votre animation.

Ce que vous pouvez compter sur, c'est que la borne valeurs que vous avez donné à votre animation de l'objet sont toujours là, avec une valeur équivalente (mais pas nécessairement pointeur de l'équivalence) dans la réplique de l'animation de l'objet passé avec l' animationDidStop:finished: message. Comme mentionné ci-dessus, l'utilisation KVC et vous obtenez la portée suffisante pour stocker et récupérer de l'etat.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X