2010-07-14 12 views
5

Ésta ha sido la conducción me nueces ...¿Fuerza la dirección de rotación de CALayer?

Teniendo en cuenta "plano" es una CALayer, puedo rotar en el eje X:

plane.transform = CATransform3DMakeRotation(180 * M_PI/180.0f, 1.0f, 0.0f, 0.0f); 

y esto hace que gire hacia la derecha, lo cual es perfecto.

Ahora, en algún momento en el tiempo, quiero que vuelva a 0 grados, así que uso:

plane.transform = CATransform3DMakeRotation(0 * M_PI/180.0f, 1.0f, 0.0f, 0.0f); 

La cosa es que ... lo hace en sentido contrario a las agujas del reloj, lo cual no es lo que yo quiero :(

Supongo que utiliza la ruta de rotación más corta, pero incluso si digo que vaya a 360 grados en su lugar, cuando está hecho y le digo que reinicie la animación, comienza desde 360 ​​para ir a 180, y va hacia atrás en lugar de la dirección correcta.

¿Hay alguna manera de solucionar eso?

lo que he hecho en Actionscript sería:

if (plane.rotationX == 360) plane.rotationX = 0; 

y sería reanudar muy bien, pero si lo hago que el uso de CATransform3DMakeRotation ambas transformaciones chocan entre sí, debido a la animación (creo) y se ensucia.

¡Cualquier ayuda sería muy apreciada!

Gracias

+0

veo esta es una decisión difícil :( – Andre

Respuesta

8

Esta pregunta surgió cuando estaba buscando resolver un problema similar. Quería rotar una imagen 180 grados y luego quería seguir girando para dar un salto mortal completo. iOS quería volver a tomar la ruta más corta. La respuesta aquí no me ayudó demasiado. Terminé buscando algunas cosas en las animaciones de KeyPath y eso resolvió mi problema. A continuación se muestra un ejemplo del enfoque.

Para el problema particular planteado en la pregunta, necesitaría dos conjuntos diferentes de keyFrameValues, uno para la rotación inicial y otro para la segunda. Pero al poner en un valor intermedio puede obtener el efecto deseado, es decir, tomar el camino más largo o forzar la elección de caminos igualmente largos, si eso es lo que desea. He dejado algunos códigos de variantes en los comentarios, ya que pueden ayudar a las personas que no están familiarizadas con CAKeyFrameAnimation a seguir el código/comprender el rango de opciones.

- (void) somersault; 
{ 

    CALayer* layer = [self layer]; 
    NSMutableArray* keyFrameValues = [NSMutableArray array]; 
    [keyFrameValues addObject:[NSNumber numberWithFloat:0.0]]; 
    //[values addObject:[NSNumber numberWithFloat:M_PI*0.5]]; 
    [keyFrameValues addObject:[NSNumber numberWithFloat:M_PI]]; 
    [keyFrameValues addObject:[NSNumber numberWithFloat:M_PI*1.5]]; 
    [keyFrameValues addObject:[NSNumber numberWithFloat:M_PI*2.0]]; 

    CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; 
    [animation setValues:keyFrameValues]; 
    [animation setValueFunction:[CAValueFunction functionWithName: kCAValueFunctionRotateX]];// kCAValueFunctionRotateZ]]; 

    [animation setDuration:0.9]; 
    //[animation setTimingFunction: [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; 

    [layer addAnimation:animation forKey:nil]; 

    return; 
} 
+1

Si desea una animación constante en todo, puede establecer 'animation.calculationMode = kCAAnimationPaced' y CoreAnimation interpolará los ángulos de manera uniforme en el tiempo. – kevboh

1

Creo que su problema se ha reducido a esperar un poco demasiado del sistema de animación implícita, que es básicamente sólo va a interpolar los valores de las propiedades de la capa de A a B. Esto es ideal para una amplia variedad de casos, pero no le permite hacer cosas como "cadena" cambios juntos en secuencia. Hay formas de hacer esto último, aunque definitivamente son menos convenientes que lo que estás haciendo en este momento. Aún así, es posible que desee investigar aquellos para hacer las cosas "correctamente". (Comenzar con otro vistazo a la Core Animation Guide.)

Sin embargo, si usted está dispuesto a poner al día con una solución cursi, que puede ser capaz de conseguir esto para mirar cómo desea continuar con sólo cambiar la rotación ángulo en la misma dirección cada vez en lugar de establecer a una constante 0 o 180:

// you need to keep track of this somewhere in your code 
// (I've made it static for simplicity, you should do something more sensible) 
static long currentAngle = 0; 

// rotate (another) 180 degrees 
currentAngle += 180; 
plane.transform = CATransform3DMakeRotation(currentAngle * M_PI/180.0f, 1.0f, 0.0f, 0.0f); 

digo "podría", porque algo en su descripción no hace realmente carillón con cómo iba a esperar la transformación para trabajar, y hay claramente algunas sutilezas de implementación que no prope lo entiendo. Este enfoque bien puede fallar. Pero es trivialmente simple, por lo que probablemente valga la pena intentarlo.

+0

Gracias por su ayuda. Por desgracia que había intentado ya, sólo que no funcionó porque mis aviones son de dos vías y la rotación acumulada se arruina. Como una referencia, esto es lo que intento replicar: www.assalino.com (la pila 3D después de la introducción). Lo hice en AS3 y es relativamente simple. La clave es poder cambiar la rotación de -180 a 180 (por ejemplo) sin animación. La única forma que he encontrado para hacerlo en Core Animation es cambiando la propiedad de duración a 0 para ese cambio y luego volver a establecerla para la animación final, pero se superponen y no funciona. – Andre

+0

@Andre Tu Flash no funcionó para mí (y realmente, la vida es muy corta), así que tal vez me falta algo, pero no estoy seguro de cómo El hecho de que los aviones vayan en ambos sentidos debería afectar la rotación acumulada; si funciona de una manera, debería funcionar la otra. En cualquier caso, si este truco no funciona, creo que tendrá que renunciar a la animación implícita y usar explícitamente en su lugar: puede detener e iniciar a voluntad, especificar secuencias de valores y tiempos, recibir notificaciones cuando completen, etc. – walkytalky

0

Para mí funciona tal solución. Agrega un valor de rotación intermedio para mostrar en qué dirección se debe girar la vista. Entonces no necesita CAKeyframeAnimation.

if backwardDirection { 
    view.transform = CGAffineTransform(rotationAngle: -CGFloat.pi/2) 
    view.transform = CGAffineTransform(rotationAngle: 0) 
} else { 
    view.transform = CGAffineTransform(rotationAngle: -CGFloat.pi/2) 
    view.transform = CGAffineTransform(rotationAngle: -CGFloat.pi) 
} 
Cuestiones relacionadas