Jak anulować animację opartą na blokach UIView?

86

Przeszukałem mnóstwo rzeczy SO i referencji Apple, ale nadal nie mogę poradzić sobie z moim problemem.

Co ja mam:

  1. Ekran z podłączonymi UIImageView2 UIButtonsi 2 s
  2. 2 rodzaje animacji:
    1. Skalowanie w górę, a następnie w dół każdego obrazu, jeden po drugim, tylko raz viewDidLoad
    2. Naciśnięcie przycisku (niestandardowy przycisk ukryty „wewnątrz” każdego przycisku UIImageView) uruchamia animację odpowiedniego - UIImageViewtylko jednego, a nie obu - (również skalowanie w górę, a następnie w dół).
    3. Kiedy piszę dla iOS4 +, powiedziano mi, żebym używał animacji blokowych!

Czego potrzebuję:

Jak anulować uruchomioną animację? Udało mi się zrezygnować mimo wszystko oprócz ostatniego ...: /

Oto mój fragment kodu:

[UIImageView animateWithDuration:2.0 
                               delay:0.1 
                             options:UIViewAnimationOptionAllowUserInteraction 
                          animations:^{
        isAnimating = YES;
        self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 2.0, 2.0);
    } completion:^(BOOL finished){
        if(! finished) return;
        [UIImageView animateWithDuration:2.0 
                                   delay:0.0 
                                 options:UIViewAnimationOptionAllowUserInteraction 
                              animations:^{
            self.bigLetter.transform = CGAffineTransformScale(self.bigLetter.transform, 0.5, 0.5);
        } completion:^(BOOL finished){
            if(! finished) return;
            [UIImageView animateWithDuration:2.0 
                                       delay:0.0 
                                     options:UIViewAnimationOptionAllowUserInteraction 
                                  animations:^{
                self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 2.0, 2.0);
            } completion:^(BOOL finished){
                if(! finished) return;
                [UIImageView animateWithDuration:2.0 
                                           delay:0.0 
                                         options:UIViewAnimationOptionAllowUserInteraction 
                                      animations:^{
                    self.smallLetter.transform = CGAffineTransformScale(self.smallLetter.transform, 0.5, 0.5);
                }
                                      completion:^(BOOL finished){
                                          if (!finished) return;
                                          //block letter buttons
                                          [self.bigLetterButton setUserInteractionEnabled:YES];
                                          [self.smallLetterButton setUserInteractionEnabled:YES];
                                          //NSLog(@"vieDidLoad animations finished");
                                      }];
            }];
        }];
    }];

Jakoś smallLetter UIImageViewnie działa poprawnie, bo po wciśnięciu (przez przycisk) bigLetteranimacje są poprawnie anulowane ...

EDYCJA: Użyłem tego rozwiązania, ale nadal mam problem ze skalowaniem w dół smallLetter UIImageView- nie anulowałem wcale ... rozwiązanie

EDIT2: dodałem to na początku metod next / prev:

- (void)stopAnimation:(UIImageView*)source {
    [UIView animateWithDuration:0.01
                          delay:0.0 
                        options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction)
                     animations:^ {
                         source.transform = CGAffineTransformIdentity;
                     }
                     completion:NULL
     ];
}

problem pozostaje ...: / nie mam pojęcia jak przerwać ostatnią animację dla liter w łańcuchu animacji

Raistlin
źródło
Hej, myślę, że odpowiedź Hariego Kunwara powinna zostać zaakceptowana teraz.
marczellm
W dzisiejszych czasach musisz użyć UIViewPropertyAnimator - jest to również znacznie łatwiejsze.
Fattie

Odpowiedzi:

151

Możesz zatrzymać wszystkie animacje w widoku, wywołując:

[view.layer removeAllAnimations];

(Będziesz musiał zaimportować platformę QuartzCore, aby wywoływać metody w pliku view.layer).

Jeśli chcesz zatrzymać określoną animację, a nie wszystkie animacje, najlepszym rozwiązaniem jest jawne użycie CAAnimations zamiast metod pomocniczych animacji UIView, wtedy będziesz mieć bardziej szczegółową kontrolę i możesz zatrzymać animacje jawnie według nazwy.

Dokumentację Apple Core Animation można znaleźć tutaj:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/CreatingBasicAnimations/CreatingBasicAnimations.html

Nick Lockwood
źródło
10
Chcę tylko dodać, w mojej własnej obserwacji, kolejne animateWithDuration nie działają już po wywołaniu removeAllAnimations. Służy do paginacji i ciągnięcia w celu odświeżenia kontrolek, być może ktoś inny może zaobserwować coś innego. W końcu używam CABasicAnimation i wywołuję [myView.layer removeAnimationForKey: @ "animationKey"];
Zhang
Dzięki za wskazówkę @Nick - tylko uwaga, że ​​link nie wydaje się już być obsługiwany, spróbuj zamiast tego: developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ ...
trdavidson
52

W przypadku systemu iOS 10 do animowania użyj UIViewPropertyAnimator. Zapewnia metody uruchamiania, zatrzymywania i wstrzymywania animacji UIView.

 let animator = UIViewPropertyAnimator(duration: 2.0, curve: .easeOut){
        self.view.alpha = 0.0
 }
 // Call this to start animation.
 animator.startAnimation()

 // Call this to stop animation.
 animator.stopAnimation(true)
Hari Kunwar
źródło
3

Dodam do odpowiedzi Nicka, że ​​uczynienie removeAllAnimations płynnym następnym pomysłem będzie bardzo przydatne.

[view.layer removeAllAnimations];
[UIView transitionWithView:self.redView
                  duration:1.0f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
                      [view.layer displayIfNeeded];
                  } completion:nil];
Gaston Morixe
źródło
0

Możesz spróbować tego (w Swift):

UIView.setAnimationsEnabled(false)
UIView.setAnimationsEnabled(true)

Uwaga: w razie potrzeby możesz umieścić kod między tymi dwoma wywołaniami, na przykład:

UIView.setAnimationsEnabled(false)
aview.layer.removeAllAnimations() // remove layer based animations e.g. aview.layer.opacity
UIView.setAnimationsEnabled(true)
iAmcR
źródło