Question

Est-il possible d'annuler une animation UIView alors qu'il est en cours? Ou devrais-je laisser tomber au niveau de CA?

i.e.. Je l'ai fait quelque chose comme ça (peut-être une mise en action d'animation de fin aussi):

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve: UIViewAnimationCurveLinear];
// other animation properties

// set view properties

[UIView commitAnimations];

Mais avant que l'animation se termine et je reçois l'animation terminée événement, je veux l'annuler (couper court). Est-ce possible? Googler trouve autour de quelques personnes posent la même question sans réponse -. Et une ou deux personnes qui spéculent qu'il ne peut pas être fait

Était-ce utile?

La solution

La façon dont je le fais est de créer une nouvelle animation à votre point final. Définir une très courte durée et assurez-vous d'utiliser la méthode de +setAnimationBeginsFromCurrentState: à partir de l'état actuel. Lorsque vous le réglez sur OUI, l'animation en cours est interrompue. On dirait quelque chose comme ceci:

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.1];
[UIView setAnimationCurve: UIViewAnimationCurveLinear];
// other animation properties

// set view properties

[UIView commitAnimations];

Autres conseils

Utilisation:

#import <QuartzCore/QuartzCore.h>

.......

[myView.layer removeAllAnimations];

Simplest façon d'arrêter tous animations sur une vue particulière, immédiatement , est ceci:

Lier le projet à QuartzCore.framework. Au début de votre code:

#import <QuartzCore/QuartzCore.h>

Maintenant, quand vous voulez arrêter toutes les animations sur une mort vue dans leurs voies, dire ceci:

[CATransaction begin];
[theView.layer removeAllAnimations];
[CATransaction commit];

La ligne médiane fonctionnerait tout seul, mais il y a un délai jusqu'à ce que les finitions runloop (le « redessiner moment »). Pour éviter ce délai, envelopper la commande dans un bloc de transaction explicite comme indiqué. Cela fonctionne à condition qu'aucune autre modification n'a été effectuée sur cette couche dans la runloop actuelle.

Sur iOS 4 et supérieur, utiliser l'option UIViewAnimationOptionBeginFromCurrentState sur la deuxième animation à couper la première animation court.

À titre d'exemple, supposons que vous avez une vue avec un indicateur d'activité. Vous souhaitez effacer l'indicateur d'activité pendant une activité chronophage potentiellement commence et fade quand l'activité est terminée. Dans le code ci-dessous, la vue avec l'indicateur d'activité sur elle est appelée activityView.

- (void)showActivityIndicator {
    activityView.alpha = 0.0;
    activityView.hidden = NO;
    [UIView animateWithDuration:0.5
                 animations:^(void) {
                     activityView.alpha = 1.0;
                 }];

- (void)hideActivityIndicator {
    [UIView animateWithDuration:0.5
                 delay:0 options:UIViewAnimationOptionBeginFromCurrentState
                 animations:^(void) {
                     activityView.alpha = 0.0;
                 }
                 completion:^(BOOL completed) {
                     if (completed) {
                         activityView.hidden = YES;
                     }
                 }];
}

Pour annuler une animation il vous suffit de définir la propriété qui est en cours d'animation, en dehors de l'animation UIView. Qui arrêtera l'animation là où elle est, et le UIView sauteront au paramètre que vous venez de définir.

Désolé de ressusciter cette réponse, mais dans iOS 10 choses un peu changé, et maintenant l'annulation est possible et vous pouvez même annuler grâce!

Après iOS 10, vous pouvez annuler les animations avec UIViewPropertyAnimator !

UIViewPropertyAnimator(duration: 2, dampingRatio: 0.4, animations: {
    view.backgroundColor = .blue
})
animator.stopAnimation(true)

Si vous passez vrai, il annule l'animation et il arrête là où vous l'avez annulée. La méthode d'achèvement ne sera pas appelé. Cependant, si vous passez faux, vous êtes responsable de l'animation de finition:

animator.finishAnimation(.start)

Vous pouvez terminer votre animation et de rester dans l'état actuel (.current) ou allez à l'état initial (.start) ou à l'état final (.end)

Par ailleurs, vous pouvez même faire une pause et redémarrer plus tard ...

animator.pauseAnimation()
animator.startAnimation()

Note: Si vous ne voulez pas une brusque annulation vous pouvez inverser votre animation ou même changer votre animation après vous mettre en pause

Si vous animez une contrainte en changeant la constante au lieu d'un pas de propriétés de vue des autres méthodes fonctionnent sur iOS 8.

Exemple animation:

self.constraint.constant = 0;
[self.view updateConstraintsIfNeeded];
[self.view layoutIfNeeded];
[UIView animateWithDuration:1.0f
                      delay:0.0f
                    options:UIViewAnimationOptionCurveLinear
                 animations:^{
                     self.constraint.constant = 1.0f;
                     [self.view layoutIfNeeded];
                 } completion:^(BOOL finished) {

                 }];

Solution:

Vous devez supprimer les animations des couches de toutes les vues sont affectées par le changement de contrainte et de leurs sous-couches.

[self.constraintView.layer removeAllAnimations];
for (CALayer *l in self.constraintView.layer.sublayers)
{
    [l removeAllAnimations];
}

Si vous voulez juste faire une pause / arrêt animation en douceur

self.yourView.layer.speed = 0;

Source: Comment faire pour mettre en pause l'animation d'un arbre couche

Aucune de ces résolu pour moi, mais cela a aidé: L'animation UIView définit la propriété immédiatement, puis l'anime. Il arrête l'animation lorsque la couche de présentation correspond au modèle (la propriété définie).

Je résolu mon problème, ce qui était « Je veux animer d'où vous regardez comme vous semblez » (ce qui signifie « vous » le point de vue). Si vous voulez que, alors:

  1. Ajouter QuartzCore.
  2. CALayer * pLayer = theView.layer.presentationLayer;

régler la position de la couche de présentation

J'utilise quelques options, y compris UIViewAnimationOptionOverrideInheritedDuration

Mais parce que la documentation d'Apple est vague, je ne sais pas si elle remplace vraiment les autres animations quand il est utilisé, ou remet à zéro juste minuteries.

[UIView animateWithDuration:blah... 
                    options: UIViewAnimationOptionBeginFromCurrentState ... 
                    animations: ^ {
                                   theView.center = CGPointMake( pLayer.position.x + YOUR_ANIMATION_OFFSET, pLayer.position.y + ANOTHER_ANIMATION_OFFSET);
                   //this only works for translating, but you get the idea if you wanna flip and scale it. 
                   } completion: ^(BOOL complete) {}];

Et cela devrait être une solution décente pour l'instant.

[UIView setAnimationsEnabled:NO];
// your code here
[UIView setAnimationsEnabled:YES];

J'ai le même problème; les API n'ont rien d'annuler une animation spécifique. Le

+ (void)setAnimationsEnabled:(BOOL)enabled

désactive toutes les animations, et donc ne fonctionne pas pour moi. Il y a deux solutions:

1) faire de votre objet animé d'un sous-vue. Ensuite, lorsque vous voulez annuler les animations pour ce point de vue, retirez la vue ou le cacher. Très simple, mais vous devez recréer la sous-vue sans animations si vous avez besoin de le garder en vue.

2) répéter l'anim seul, et faire un sélecteur de délégué pour redémarrer l'anim si nécessaire, comme ceci:

-(void) startAnimation {
NSLog(@"startAnim alpha:%f", self.alpha);
[self setAlpha:1.0];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(pulseAnimationDidStop:finished:context:)];
[self setAlpha:0.1];
[UIView commitAnimations];
}

- (void)pulseAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
if(hasFocus) {
    [self startAnimation];
} else {
    self.alpha = 1.0;
}
}

-(void) setHasFocus:(BOOL)_hasFocus {
hasFocus = _hasFocus;
if(hasFocus) {
    [self startAnimation];
}
}

Problème 2) est qu'il ya toujours retarder l'arrêt de l'anim comme il se termine le cycle d'animation en cours.

Hope this helps.

Même si vous annulez l'animation de la manière ci-dessus animation didStopSelector fonctionne toujours. Donc, si vous avez des états logiques dans votre application tirée par des animations vous aurez des problèmes. Pour cette raison, les moyens décrits ci-dessus, j'utiliser la variable contexte des animations UIView. Si vous passez l'état actuel de votre programme par le param contexte à l'animation, lorsque l'animation se fige votre fonction didStopSelector peut décider si elle doit faire quelque chose ou tout simplement revenir en fonction de l'état actuel et la valeur d'état passé en contexte.

Version Swift de la solution de Stephen Darlington

UIView.beginAnimations(nil, context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(0.1)
// other animation properties

// set view properties
UIView.commitAnimations()
CALayer * pLayer = self.layer.presentationLayer;
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView animateWithDuration:0.001 animations:^{
    self.frame = pLayer.frame;
}];

Pour mettre en pause une animation sans revenir à l'état initial ou final:

CFTimeInterval paused_time = [myView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
myView.layer.speed = 0.0;
myView.layer.timeOffset = paused_time;

Quand je travaille avec animation UIStackView, en plus removeAllAnimations() je dois fixer des valeurs initiales parce que l'un removeAllAnimations() peut les mettre à l'état imprévisible. Je stackView avec view1 et view2 à l'intérieur, et un point de vue doit être visible et un caché:

public func configureStackView(hideView1: Bool, hideView2: Bool) {
    let oldHideView1 = view1.isHidden
    let oldHideView2 = view2.isHidden
    view1.layer.removeAllAnimations()
    view2.layer.removeAllAnimations()
    view.layer.removeAllAnimations()
    stackView.layer.removeAllAnimations()
    // after stopping animation the values are unpredictable, so set values to old
    view1.isHidden = oldHideView1 //    <- Solution is here
    view2.isHidden = oldHideView2 //    <- Solution is here

    UIView.animate(withDuration: 0.3,
                   delay: 0.0,
                   usingSpringWithDamping: 0.9,
                   initialSpringVelocity: 1,
                   options: [],
                   animations: {
                    view1.isHidden = hideView1
                    view2.isHidden = hideView2
                    stackView.layoutIfNeeded()
    },
                   completion: nil)
}

Aucune des solutions répondues travaillé pour moi. Je résolu mes problèmes de cette façon (je ne sais pas si elle est une bonne façon?), Parce que j'avais des problèmes lors de l'appel de cette trop rapide (lorsque l'animation précédente était pas encore fini). Je passe ma recherché animation avec customAnim bloc.

extension UIView
{

    func niceCustomTranstion(
        duration: CGFloat = 0.3,
        options: UIView.AnimationOptions = .transitionCrossDissolve,
        customAnim: @escaping () -> Void
        )
    {
        UIView.transition(
            with: self,
            duration: TimeInterval(duration),
            options: options,
            animations: {
                customAnim()
        },
            completion: { (finished) in
                if !finished
                {
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    // NOTE: This fixes possible flickering ON FAST TAPPINGS
                    self.layer.removeAllAnimations()
                    customAnim()
                }
        })

    }

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