Question

Je me demande où sont les rappels (ou s'il y a quoi que ce soit) pour les animations dans un CALayer. Plus précisément, pour les animations implicites telles que la modification du cadre, de la position, etc. Dans une vue UIV, vous pouvez faire quelque chose comme ceci:

[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, le setAnimationDidStopSelector est ce que je veux pour une animation dans une couche CAL. Y a-t-il quelque chose comme ça?

TIA.

Était-ce utile?

La solution 2

J'ai répondu à ma propre question. Vous devez ajouter une animation à l'aide de CABasicAnimation comme suit:

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 de délégation animationDidStop: terminé: et vous devriez être prêt à partir. Dieu merci, cette fonctionnalité existe! : D

Autres conseils

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

Nous avons perdu 4 heures avec cette poubelle, histoire de 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() 

Pour 2018 ...

Swift 4.

utilisez .setCompletionBlock

En pratique, vous avez besoin de [moi auto] ou vous planterez généralement.

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 se fait appeler à nouveau.

Bien sûr, vous pouvez appeler n’importe quelle fonction.

Remarque: si vous commencez tout juste. Il convient de rappeler que

  1. la "touche" " (comme dans add # forKey ) n'est pas pertinent et est rarement utilisé. Réglez-le à zéro. Si, pour une raison quelconque, vous souhaitez le définir, définissez-le sur "toute chaîne". (dites votre pseudo). Par contre ...

  2. Le keyPath de 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 juste écrit sous forme de chaîne).

En bref, add # forKey est presque toujours nul, il est sans importance. Il est totalement, complètement, sans rapport avec le "keyPath". - le fait qu'ils ont tous les deux la " clé " dans le nom est une pure coïncidence, les deux choses sont totalement indépendantes.

Vous voyez souvent du code où ces deux noms sont confondus (grâce à l'appellation 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 donnée 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 de dessins animés différents (ce qui est souvent le cas), utilisez simplement des blocs de complétion.

Juste une note pour ceux qui trouvent cette page sur Google: vous pouvez vraiment faire le travail en configurant le "délégué". propriété de votre objet animation sur l’objet qui recevra la notification et implémentera le " animationDidStop " méthode dans le fichier .m de cet objet. 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 délégué 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()
}

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’objetAnimation fourni pour réaliser des fonctionnalités spécifiques en fonction de l’animation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top