2012-02-13 12 views
5

Estoy tratando de aplicar un efecto de cámara lenta a mi aplicación, más o menos como puede reducir la velocidad de la mayoría de los efectos gráficos de Mac OS si presiona Shift.Reduzca la velocidad y acelere las animaciones con CoreAnimation

Mi aplicación utiliza CoreAnimation, así que pensé que debería ser no hay problema: Conjunto speed a un valor más lento (como 0.1) y la puso de nuevo a 1 una vez que he terminado, y aquí voy.

Parece que, lamentablemente, esta no es la manera correcta. La ralentización funciona muy bien, sin embargo, cuando quiero volver a la velocidad normal, se reanuda como si la velocidad fuera 1 todo el tiempo. Esto básicamente significa que si sostuve Shift por el tiempo suficiente, tan pronto como lo suelte, la animación se completa al instante.

Encontré una página de garantía de calidad técnica que explica cómo pausar y reanudar una animación, pero parece que no puedo hacerlo bien si no se trata de detener por completo la animación. Definitivamente no soy muy bueno en el cambio de tiempo.

¿Cuál sería la forma correcta de reducir la velocidad y luego reanudar una animación con CoreAnimation?

Aquí está el código útil:

-(void)flagsChanged:(NSEvent *)theEvent 
{ 
    CALayer* layer = self.layer; 
    [CATransaction begin]; 
    CATransaction.disableActions = YES; 
    layer.speed = (theEvent.modifierFlags & NSShiftKeyMask) ? 0.1 : 1; 
    [CATransaction commit]; 
} 
+1

que suelen tener cambio sólo se aplica a las animaciones comenzado mientras cambio se lleva a cabo, y dejando de lado no lo hace al instante acelerar la animación Esto generalmente se puede lograr simplemente haciendo que la duración de la animación dependa de si se mantiene presionada la tecla shift en el momento en que se crea la animación. –

+1

@Kevin Ballard, lo sé; pero aparte de que es un efecto genial, posiblemente también será útil en mi contexto para poder ralentizarlo en cualquier momento. – zneak

+0

Bueno, creo que cuando cambias la velocidad, también deberás calcular una compensación de tiempo para aplicar de modo que la velocidad anterior * time == newspeed * time + offset –

Respuesta

4

problema difícil ...

puedo configurar una prueba con un UIView básica. Inicié una animación de su capa desde su punto actual hasta un punto objetivo.

Para ralentizar la animación del núcleo, en realidad tuve que construir y reemplazar una nueva animación (ya que no puede modificar la animación existente).

Es especialmente importante determinar cuán lejos ha avanzado la animación actual. Esto se hace accediendo a beginTime, currentTime, calculando el tiempo transcurrido y luego calculando cuánto tiempo debe durar la nueva animación.

- (void)initiate { 
    if(!initiated) { 
     [CATransaction begin]; 
     [CATransaction disableActions]; 
     [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut]]; 
     CABasicAnimation *ba = [CABasicAnimation animationWithKeyPath:@"position"]; 
     ba.duration = 10.0f; 
     ba.fromValue = [NSValue valueWithCGPoint:view.layer.position]; 
     ba.toValue = [NSValue valueWithCGPoint:CGPointMake(384, 512)]; 
     [view.layer addAnimation:ba forKey:@"animatePosition"]; 
     [CATransaction commit]; 
     initiated = YES; 
    } 
} 

- (void)slow { 
    [CATransaction begin]; 
    CABasicAnimation *old = (CABasicAnimation *)[view.layer animationForKey:@"animatePosition"]; 
    CABasicAnimation *ba = [CABasicAnimation animationWithKeyPath:@"position"]; 
    CFTimeInterval animationBegin = old.beginTime; 
    CFTimeInterval currentTime = CACurrentMediaTime(); 
    CFTimeInterval elapsed = currentTime - animationBegin; 
    ba.duration = [[old valueForKey:@"duration"] floatValue] - elapsed; 
    ba.duration = [[old valueForKey:@"duration"] floatValue]; 
    ba.autoreverses = [[old valueForKey:@"autoreverses"] boolValue]; 
    ba.repeatCount = [[old valueForKey:@"repeatCount"] floatValue]; 
    ba.fromValue = [NSValue valueWithCGPoint:((CALayer *)[view.layer presentationLayer]).position]; 
    ba.toValue = [old valueForKey:@"toValue"]; 
    ba.speed = 0.1; 
    [view.layer addAnimation:ba forKey:@"animatePosition"]; 
    [CATransaction commit]; 
} 

- (void)normal { 
    [CATransaction begin]; 
    CABasicAnimation *old = (CABasicAnimation *)[view.layer animationForKey:@"animatePosition"]; 
    CABasicAnimation *ba = [CABasicAnimation animationWithKeyPath:@"position"]; 
    CFTimeInterval animationBegin = old.beginTime; 
    CFTimeInterval currentTime = CACurrentMediaTime(); 
    CFTimeInterval elapsed = currentTime - animationBegin; 
    ba.duration = [[old valueForKey:@"duration"] floatValue] - elapsed; 
    ba.autoreverses = [[old valueForKey:@"autoreverses"] boolValue]; 
    ba.repeatCount = [[old valueForKey:@"repeatCount"] floatValue]; 
    ba.fromValue = [NSValue valueWithCGPoint:((CALayer *)[view.layer presentationLayer]).position]; 
    ba.toValue = [old valueForKey:@"toValue"]; 
    ba.speed = 1; 
    [view.layer addAnimation:ba forKey:@"animatePosition"]; 
    [CATransaction commit]; 
} 

Nota: El código anterior funciona sólo en 1 dirección, no con animaciones que AutoReverse ...

+1

Publiqué mi código. – zneak

Cuestiones relacionadas