2012-03-21 8 views
8

Mam zestaw zagnieżdżonych animacji UIView (2 lub 3 poziomy głębokie w danym momencie), które chciałbym móc wstrzymać i wznowić. Niektóre z tych animacji używają -animateWithDuration:animations:completion:, podczas gdy inne używają -animateWithDuration:delay:options:animations:completion: w celu opóźnienia wykonania bloku animacji.Wstrzymywanie animacji CALayer z animacją z opóźnieniem

Przeczytałem i zaimplementowałem Technical Q&A QA1673 o wstrzymaniu wszystkich animacji w drzewie warstw, ale napotykam problem z animacjami, które używają parametru opóźnienia. Mogę wstrzymać i wznowić animacje, ale po wznowieniu animacji, blok animacji, który ma opóźnienie, wydaje się mieć wydłużone opóźnienie o czas, w którym drzewo zostało zatrzymane. Na przykład jeśli jeden z bloków ma opóźnienie o 1 sekundę, a drzewo warstw zostało wstrzymane na 3 sekundy, animacja opóźnia się po 4 sekundach po wznowieniu. Zgaduję, że ma to coś wspólnego z własnością beginTime? Każda pomoc będzie doceniona.

// Pause and Resume methods, right from the technical Q&A 
- (void)pauseAnimationsOnLayer:(CALayer *)layer 
{ 
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; 
    layer.speed = 0.0; 
    layer.timeOffset = pausedTime; 
} 

- (void)resumeAnimationsOnLayer:(CALayer *)layer 
{ 
    CFTimeInterval pausedTime = [layer timeOffset]; 
    layer.speed = 1.0; 
    layer.timeOffset = 0.0; 
    layer.beginTime = 0; 
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; 
    layer.beginTime = timeSincePause; 
} 

// Chained animations 
- (void)animateNextPopup 
{ 
    [UIView animateWithDuration:kRFPVictorySequenceStatePopupDuration 
        animations:^{ 
         [_currentStateImageView setHidden:NO]; 
         [_currentStateImageView setTransform:CGAffineTransformIdentity]; 

        } 
        completion:^(BOOL finished) { 
         [UIView animateWithDuration:kRFPVictorySequenceStateSlideOffDuration 
               delay:kRFPVictorySequenceStateVoteDelay 
              options:UIViewAnimationOptionCurveEaseInOut 
              animations:^{ 
               if (winnerIsDem) { 
                [_currentStateImageView setFrame:CGRectMake(-_currentStateImageView.frame.size.width, 
                           _currentStateImageView.frame.origin.y, 
                           _currentStateImageView.frame.size.width, 
                           _currentStateImageView.frame.size.height)]; 
               } 
               else { 
                [_currentStateImageView setFrame:CGRectMake(1024, 
                           _currentStateImageView.frame.origin.y, 
                           _currentStateImageView.frame.size.width, 
                           _currentStateImageView.frame.size.height)]; 
               } 
              } 
              completion:^(BOOL finished) { 
               // Do some stuff 
              } 
          ]; 
        } 
    ]; 
} 

Odpowiedz

0

Proponuję inne podejście.

Bloki animacji są łatwe do wdrożenia, ale przydatne tylko wtedy, gdy nie potrzebujesz żadnej kontroli nad animacją.

W przeciwnym razie należy użyć timera i ręcznie utworzyć własną animację.

[NSTimer scheduledTimerWithTimeInterval:0.1 
           target:self 
           selector:@selector(timerFired) 
           userInfo:nil 
           repeats:YES]; 

- (void)timerFired 
{ 
    if (isPaused) { 
     // Do nothing 
    } else { 
     // Animate 
    } 
} 

- (IBAction)pauseTapped:(id)sender 
{ 
    if (isPaused) { 
     isPaused = NO; 
    } else { 
     isPaused = YES; 
    } 
} 

isPaused to flaga sterująca Twoim stanem animacji.

+2

Dzięki za odpowiedź, ale ten pomysł ma również swoje własne problemy. Użycie standardowego 'NSTimer' nie zsynchronizuje animacji z wyświetlaną szybkością urządzenia, co może spowodować, że animacja będzie wyglądała na wzburzoną. Lepiej byłoby użyć 'CADisplayLink', który jest podobny, ale zaprojektowany dokładnie w celu synchronizacji z wyświetlaczem. Mimo to używanie jednego obiektu łącza wyświetlania do uruchamiania ~ 10 zserializowanych animacji może spowodować poważne kodowanie spaghetti. Ostatecznie moje pytanie brzmi: * dlaczego * wstrzymywanie animacji w drzewie warstw wpływa na wartości opóźnień dla * kolejnych * animacji? Wydaje się dziwne, nie? – Sean

+0

"jakiś poważny kod spaghetti" ... tak, masz rację ... ale przecież jestem Włochem;) – Beppe

0

Znalazłem rozwiązanie problemu! Musisz zresetować wartość self.layer.beginTime do zera w bloku zakończenia twoich animacji.

np.

[UIView animateWithDuration:element.duration 
         delay:element.delay 
        options:UIViewAnimationOptionCurveLinear 
       animations:^{ 
         // Animate properties here! 
        } 
       } completion:^(BOOL finished){ 
           // Reset BeginTime all the time 
           // So, in case a pause took place the delay values are valid again! 
         **self.layer.beginTime = 0.0f;** 
       }]; 

Reszta kodu pauzy/wznowienia pozostaje dokładnie taka sama.

Najlepsza!

+0

Darn Miałem nadzieję, że to zadziała ... ale to nie dla mnie :(, nie ma żadnego efektu, na razie decyduję się na usunięcie opóźnienia poprzez blok animacji – cclogg

+0

@ cclogg jeśli masz wiele animacji bloków uruchomionych na tej samej warstwie, musisz ustawić ją raz, nie w każdej animacji bloku :) – Summon