2012-03-21 12 views
8

Tengo un conjunto de animaciones UIView anidadas (2 o 3 niveles de profundidad en un momento dado) que me gustaría poder detener y reanudar. Algunas de estas animaciones usan -animateWithDuration:animations:completion:, mientras que otras usan -animateWithDuration:delay:options:animations:completion: para retrasar la ejecución del bloque de animación.Pausar animación CALayer con una animación con un retraso

He leído e implementado Technical Q&A QA1673 sobre pausar todas las animaciones en un árbol de capas, pero estoy teniendo un problema con las animaciones que usan un parámetro de retraso. Puedo pausar y reanudar animaciones muy bien, pero cuando la animación se reanuda, cualquier bloque de animación que tenga un retraso asociado con él parece tener su retraso extendido por la cantidad de tiempo que el árbol de capas estuvo en pausa. Entonces, por ejemplo, si uno de los bloques tiene un retraso de 1 segundo, y el árbol de capas se detuvo por 3 segundos, la animación se retrasa por 4 segundos después de reanudar. Supongo que esto tiene algo que ver con la propiedad beginTime. Cualquier ayuda sería apreciada.

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

Respuesta

0

Sugiero un enfoque diferente.

Los bloques de animación son fáciles de implementar, pero solo son útiles si no necesita ningún control sobre su animación.

De lo contrario, debe usar un temporizador y crear su propia animación manualmente.

[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 es una bandera que controlan su estado de animación.

+2

Gracias por la respuesta, pero esta idea también tiene sus propios problemas. El uso de un 'NSTimer' estándar no sincronizará la animación con la velocidad de visualización del dispositivo, lo que puede hacer que la animación se vea entrecortada. Sería mejor usar un 'CADisplayLink' que es similar pero diseñado exactamente con el propósito de sincronizar con la pantalla. Aún así, el uso de un objeto de enlace de visualización para ejecutar ~ 10 animaciones serializadas podría dar como resultado un código de spaghetti serio. En última instancia, mi pregunta es * ¿por qué * pausar las animaciones en un árbol de capas afecta los valores de retraso para * posteriores * animaciones? Parece extraño, ¿no? – Sean

+0

"un código serio de espaguetis" ... sí, tienes razón ... pero después de todo soy italiano;) – Beppe

0

¡He encontrado la solución al problema! Debe restablecer el valor de self.layer.beginTime a cero en el bloque de finalización de sus animaciones.

p. Ej.

[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;** 
       }]; 

El resto del código de pausa/reanudación permanece exactamente igual.

¡Lo mejor!

+0

Maldición, esperaba que esto funcionara ... pero no lo hizo para mí :(, tenía no hay efecto. Por ahora me estoy decidiendo a eliminar el retraso a través del bloque de animación. – cclogg

+0

@cclogg si tiene muchas animaciones en bloque ejecutándose en la misma capa, tiene que configurarlo UNA VEZ, no en cada animación de bloque :) – Summon