Je me demande où sont les rappels (ou s'il y a quelque chose) pour les animations dans un CALayer. Plus précisément, pour les animations implicites telles que la modification du cadre, de la position, etc.
[UIView beginAnimations:@"SlideOut" context:nil];
[UIView setAnimationDuration:.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animateOut:finished:context:)];
CGRect frame = self.frame;
frame.Origin.y = 480;
self.frame = frame;
[UIView commitAnimations];
Plus précisément, la setAnimationDidStopSelector
est ce que je veux pour une animation dans un CALayer. Y a-t-il quelque chose comme ça?
TIA.
J'ai répondu à ma propre question. Vous devez ajouter une animation en utilisant CABasicAnimation
comme ceci:
CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"frame"];
anim.fromValue = [NSValue valueWithCGRect:layer.frame];
anim.toValue = [NSValue valueWithCGRect:frame];
anim.delegate = self;
[layer addAnimation:anim forKey:@"frame"];
Et implémentez la méthode déléguée animationDidStop:finished:
et vous devriez être prêt à partir. Dieu merci, cette fonctionnalité existe! :RÉ
Vous pouvez utiliser une transaction CATransaction, elle dispose d’un gestionnaire de bloc d’achèvement.
[CATransaction begin];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[pathAnimation setDuration:1];
[pathAnimation setFromValue:[NSNumber numberWithFloat:0.0f]];
[pathAnimation setToValue:[NSNumber numberWithFloat:1.0f]];
[CATransaction setCompletionBlock:^{_lastPoint = _currentPoint; _currentPoint = CGPointMake(_lastPoint.x + _wormStepHorizontalValue, _wormStepVerticalValue);}];
[_pathLayer addAnimation:pathAnimation forKey:@"strokeEnd"];
[CATransaction commit];
Gâché 4 heures avec cette poubelle, juste pour faire un fondu en fondu. Notez le commentaire dans le code.
[CATransaction begin];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.duration = 0.3;
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat:1.0f];
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeBoth;
/// [box addAnimation:animation forKey:@"j"]; Animation will not work if added here. Need to add this only after the completion block.
[CATransaction setCompletionBlock:^{
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation2.duration = 0.3;
animation2.beginTime = CACurrentMediaTime()+1;
animation2.fromValue = [NSNumber numberWithFloat:1.0f];
animation2.toValue = [NSNumber numberWithFloat:0.0f];
animation2.removedOnCompletion = NO;
animation2.fillMode = kCAFillModeBoth;
[box addAnimation:animation2 forKey:@"k"];
}];
[box addAnimation:animation forKey:@"j"];
[CATransaction commit];
Voici une réponse dans Swift 3.0 basée sur la solution de bennythemink:
// Begin the transaction
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration //duration is the number of seconds
animation.fromValue = 0
animation.toValue = 1
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
circleLayer.strokeEnd = 1.0
// Callback function
CATransaction.setCompletionBlock {
print("end animation")
}
// Do the actual animation and commit the transaction
circleLayer.add(animation, forKey: "animateCircle")
CATransaction.commit()
Swift 4.
utiliser .setCompletionBlock
En pratique, vous avez besoin de [weak self]
ou vous allez tomber en panne.
func animeExample() {
CATransaction.begin()
let a = CABasicAnimation(keyPath: "fillColor")
a.fromValue, duration = ... etc etc
CATransaction.setCompletionBlock{ [weak self] in
self?.animeExample()
}
someLayer.add(a, forKey: nil)
CATransaction.commit()
}
Dans l'exemple, il appelle simplement à nouveau.
Bien sûr, vous pouvez appeler n’importe quelle fonction.
Remarque: si vous commencez tout juste. Il faut se rappeler que
la "clé" (comme dans add#forKey
) n'est pas pertinente et est rarement utilisée. Réglez-le à zéro. Si, pour une raison quelconque, vous souhaitez le définir, définissez-le sur "n'importe quelle chaîne" (par exemple, votre surnom). D'autre part...
La keyPath
dans l'appel CABasicAnimation
est en fait la "chose que vous animez", autrement dit, il s'agit littéralement d'une propriété du calque (mais elle est simplement écrite sous forme de chaîne).
En bref, add#forKey
est presque toujours nul, ce n'est pas pertinent. C'est totalement, complètement, sans rapport avec "keyPath" - le fait qu'ils aient tous les deux "key" dans le nom est une pure coïncidence, les deux choses sont totalement indépendantes.
Vous voyez souvent du code où ces deux sont confondus (grâce à la désignation idiote), ce qui cause toutes sortes de problèmes.
Notez que depuis peu, vous pouvez utiliser animationDidStop
avec le délégué, voir la réponse par @jack ci-dessous! Dans certains cas, c'est plus facile. Parfois, il est plus facile de simplement utiliser un bloc d'achèvement. Si vous avez beaucoup d'animes différents (ce qui est souvent le cas), utilisez simplement des blocs de complétion.
Juste une remarque pour ceux qui trouvent cette page sur Google: Vous pouvez vraiment faire le travail en définissant la propriété "delegate" de votre objet animation sur l'objet qui recevra la notification et en implémentant la méthode "animationDidStop" dans le fichier .m de cet objet. fichier. Je viens d'essayer, et ça marche. Je ne sais pas pourquoi Joe Blow a dit que ce n'était pas la bonne façon.
Dans Swift 4+ je viens d'ajouter delegate
en tant que
class CircleView: UIView,CAAnimationDelegate {
...
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.delegate = self//Set delegate
Rappel de fin d'animation -
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
print("Animation END")
}
Swift 5.0
func blinkShadow(completion: @escaping (() -> Void)) {
CATransaction.begin()
let animation = CABasicAnimation(keyPath: "shadowRadius")
animation.fromValue = layer.shadowRadius
animation.toValue = 0.0
animation.duration = 0.1
animation.autoreverses = true
CATransaction.setCompletionBlock(completion)
layer.add(animation, forKey: nil)
CATransaction.commit()
}
Si vous ne voulez pas perdre votre temps avec CATransaction
. J'ai créé une extension qui encapsule le rappel dans l'objet d'animation.
Le code peut être trouvé dans cet extrait: https://gitlab.com/snippets/1786298
Et vous pouvez ensuite l'utiliser comme ceci:
let appearAnimation = CASpringAnimation(keyPath: "transform")
appearAnimation.fromValue = contentView.layer.transform
appearAnimation.toValue = CATransform3DIdentity
appearAnimation.mass = 0.65
appearAnimation.duration = appearAnimation.settlingDuration
appearAnimation.isAdditive = true
appearAnimation.onCompletion {
completed()
}
Vous pouvez définir le nom d'une animation donnée lors de la configuration de l'objet CAAnimation. Dans animationDiStop: terminé, il vous suffit de comparer le nom de l'objet Animation fourni pour exécuter une fonctionnalité spécifique en fonction de l'animation.