J'ai eu un problème où j'avais une série de séquences CATransition / CAAnimation qui se chevauchaient, dont j'avais besoin pour effectuer des opérations personnalisées lorsque les animations s'arrêtaient, mais je ne voulais qu'un seul gestionnaire de délégué pour animationDidStop.
Cependant, j'ai eu un problème, il ne semblait pas y avoir de moyen d'identifier de manière unique chaque CATransition / CAAnimation dans le délégué animationDidStop.
J'ai résolu ce problème via le système clé / valeur exposé dans le cadre de CAAnimation.
Lorsque vous démarrez votre animation, utilisez la méthode setValue sur CATransition / CAAnimation pour définir vos identificateurs et valeurs à utiliser lorsque animationDidStop se déclenche:
-(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 délégué animationDidStop:
- (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 de ceci est qu'il vous permet de conserver l'état dans le système d'appariement clé-valeur au lieu d'avoir à le stocker dans votre classe de délégué. Moins il y a de code, mieux c'est.
N'oubliez pas de consulter la référence Apple sur le codage des paires de valeurs clés .
Existe-t-il de meilleures techniques pour l'identification CAAnimation / CATransition dans le délégué animationDidStop?
Merci, --Batgar
la source
CAAnimation
l »delegate
est forte, de sorte que vous pourriez avoir besoin de le mettre ànil
éviter de conserver les cycles!Réponses:
La technique de Batgar est trop compliquée. Pourquoi ne pas profiter du paramètre forKey dans addAnimation? Il était destiné précisément à cette fin. Prenez simplement l'appel à setValue et déplacez la chaîne de clé vers l'appel addAnimation. Par exemple:
Ensuite, dans votre rappel animationDidStop, vous pouvez faire quelque chose comme:
la source
anim.removedOnCompletion = NO;
pour qu'il existe toujours quand il-animationDidStop:finished:
est appelé.Je viens de trouver un moyen encore meilleur de créer un code de complétion pour CAAnimations:
J'ai créé un typedef pour un bloc:
Et une clé que j'utilise pour ajouter un bloc à une animation:
Ensuite, si je veux exécuter un code de fin d'animation après la fin d'une CAAnimation, je me définis comme délégué de l'animation et j'ajoute un bloc de code à l'animation en utilisant setValue: forKey:
Ensuite, j'implémente une méthode animationDidStop: done:, qui vérifie un bloc à la clé spécifiée et l'exécute si elle est trouvée:
La beauté de cette approche est que vous pouvez écrire le code de nettoyage au même endroit où vous créez l'objet d'animation. Mieux encore, puisque le code est un bloc, il a accès aux variables locales dans la portée englobante dans laquelle il est défini. Vous n'avez pas à vous soucier de la configuration des dictionnaires userInfo ou d'autres absurdités du genre, et vous n'avez pas à écrire une animationDidStop: terminée: une méthode qui devient de plus en plus complexe à mesure que vous ajoutez différents types d'animations.
À vrai dire, CAAnimation devrait avoir une propriété de bloc de complétion intégrée et une prise en charge système pour l'appeler automatiquement si elle est spécifiée. Cependant, le code ci-dessus vous offre la même fonctionnalité avec seulement quelques lignes de code supplémentaire.
la source
theBlock();
été invoqué, et je pense que cela est dû au fait que la portée du bloc a été détruite.La deuxième approche ne fonctionnera que si vous définissez explicitement votre animation pour ne pas être supprimée à la fin avant de l'exécuter:
Si vous ne le faites pas, votre animation sera supprimée avant la fin, et le rappel ne la trouvera pas dans le dictionnaire.
la source
Toutes les autres réponses sont bien trop compliquées! Pourquoi n'ajoutez-vous pas simplement votre propre clé pour identifier l'animation?
Cette solution est très simple, il vous suffit d' ajouter votre propre clé à l'animation (animationID dans cet exemple)
Insérez cette ligne pour identifier l' animation1 :
et ceci pour identifier l' animation2 :
Testez-le comme ceci:
Il ne nécessite aucune variable d'instance :
la source
[animation valueForKey:@"animationID"]
Pour rendre explicite ce qui est sous-entendu d'en haut (et ce qui m'a amené ici après quelques heures perdues): ne vous attendez pas à voir l'objet d'animation original que vous avez alloué vous être renvoyé par
lorsque l'animation se termine, car
[CALayer addAnimation:forKey:]
fait une copie de votre animation.Ce sur quoi vous pouvez compter, c'est que les valeurs clés que vous avez données à votre objet d'animation sont toujours là avec une valeur équivalente (mais pas nécessairement une équivalence de pointeur) dans l'objet d'animation de réplique transmis avec le
animationDidStop:finished:
message. Comme mentionné ci-dessus, utilisez KVC et vous obtenez une grande latitude pour stocker et récupérer l'état.la source
[animation setValue:@"myanim" forKey:@"name"]
et vous pouvez même définir le calque à animer à l'aide de[animation setValue:layer forKey:@"layer"]
. Ces valeurs peuvent ensuite être récupérées dans les méthodes déléguées.valueForKey:
revientnil
pour moi, une idée pourquoi?Je peux voir la plupart des réponses objc, je vais en faire une pour swift 2.3 basé sur la meilleure réponse ci-dessus.
Pour commencer, il sera bon de stocker toutes ces clés sur une structure privée afin que le type soit sûr et que le changer à l'avenir ne vous apportera pas de bugs ennuyeux simplement parce que vous avez oublié de le changer partout dans le code:
Comme vous pouvez le voir, j'ai changé les noms des variables / animations pour que ce soit plus clair. Maintenant, définissez ces clés lorsque l'animation est créée.
(...)
Puis enfin gérer le délégué pour quand l'animation s'arrête
la source
À mon humble avis, l'utilisation de la valeur-clé d'Apple est la manière élégante de le faire: elle est spécifiquement destinée à permettre l'ajout de données spécifiques à une application à des objets.
Une autre possibilité beaucoup moins élégante est de stocker des références à vos objets d'animation et de faire une comparaison de pointeurs pour les identifier.
la source
Pour que je vérifie si 2 objets CABasicAnimation sont la même animation, j'utilise la fonction keyPath pour faire exactement comme ça.
if ([animationA keyPath] == [animationB keyPath])
la source
J'aime utiliser
setValue:forKey
: pour garder une référence de la vue que j'anime, c'est plus sûr que d'essayer d'identifier de manière unique l'animation en fonction de l'ID car le même type d'animation peut être ajouté à différentes couches.Ces deux sont équivalents:
avec celui-ci:
et dans la méthode déléguée:
la source
Xcode 9 Swift 4.0
Vous pouvez utiliser des valeurs clés pour associer une animation que vous avez ajoutée à l'animation renvoyée dans la méthode déléguée animationDidStop.
Déclarez un dictionnaire contenant toutes les animations actives et les complétions associées:
Lorsque vous ajoutez votre animation, définissez-lui une clé:
Dans animationDidStop, la magie opère:
la source