Pregunta

Estoy trabajando con un poco de Core Animation por primera vez y en el proceso de implementación de una tarjeta de juego que pueda dar la vuelta alrededor, he decidido utilizar un CALayer para mostrar el contenido (no sé cómo voy para obtener dos lados, pero eso es otra cuestión) y tengo que ser capaz de darle la vuelta, moverlo, etc ...

Estoy usando CATransaction con cierto éxito - en el fragmento a continuación, la tarjeta se mueve desde la parte inferior izquierda a la parte superior izquierda y da la vuelta. El problema es que me wa no es dar la vuelta en sentido contrario, pero no sé cómo decirle que, "Hey, vas por el camino equivocado!"


[CATransaction begin]; 
[CATransaction setValue:[NSNumber numberWithFloat:2.0f] forKey:kCATransactionAnimationDuration];
myCard.position = CGPointMake(CGRectGetMidX(self.bounds)/2,CGRectGetMidY(self.bounds)/2);
myCard.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0);
[CATransaction commit]; 

Una segunda pregunta sería: ¿cómo puedo conseguir que haga dos transformadas a la vez? He intentado anidar dos CATransactions, pero el segundo solo prevalece sobre el primero. También he intentado cambiar el vector para la rotación de ser 2D, como decir para girar alrededor de ejes X e Y, pero eso no es equivalente a apenas darle la vuelta por pi en torno a dos ejes individuales. Aquí está el código anidado.


[CATransaction begin]; 
[CATransaction setValue:[NSNumber numberWithFloat:2.0f] forKey:kCATransactionAnimationDuration];
myCard.position = CGPointMake(CGRectGetMidX(self.bounds)/2,CGRectGetMidY(self.bounds)/2);
myCard.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0); // rotate about x

  [CATransaction begin]; 
  [CATransaction setValue:[NSNumber numberWithFloat:1.0f] forKey:kCATransactionAnimationDuration];
  myCard.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0); // rotate about y
  [CATransaction commit]; 

[CATransaction commit]; 

Y aquí es con bloques de animación UIView dentro ... He añadido controles deslizantes para el ángulo, x, y, z para el vector de rotación, y t el tiempo. La traducción se lleva a cabo a través del tiempo = 2t y cada una de las rotaciones debe tomar sólo t cada uno.

[CATransaction begin]; 
[CATransaction setValue:[NSNumber numberWithFloat:t * 2] forKey:kCATransactionAnimationDuration];
myCard.position = CGPointMake(CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2);

  [UIView beginAnimations:nil context:nil];
  [UIView setAnimationDuration:t];
  myCard.transform = CATransform3DMakeRotation(angle, x, y, z);
  [UIView commitAnimations]; 

  [UIView beginAnimations:nil context:nil];
  [UIView setAnimationDuration:t];
  [UIView setAnimationDelay:t];
  myCard.transform = CATransform3DMakeRotation(angle * 2, x, y, z);
  [UIView commitAnimations];

[CATransaction commit]; 

Y aquí es donde estoy ahora: Todo funciona con una excepción. Los reveses y de rotación (empieza a girar en la dirección opuesta) cuando la tarjeta llega a pi / 2 y 3 pi * / 2. También voltea alrededor del eje x en estos puntos. Pero x y z gran trabajo. Tan cerca!

CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath,NULL,CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2*3);
CGPathAddCurveToPoint(thePath,NULL,
                      CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2*2,
                      CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2*1.5,
                      CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2);
CAKeyframeAnimation *moveAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
moveAnimation.path=thePath;
CFRelease(thePath);

CABasicAnimation *xRotation;
xRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
xRotation.fromValue = [NSNumber numberWithFloat:0.0];
xRotation.toValue = [NSNumber numberWithFloat:x * angle * M_PI];

CABasicAnimation *yRotation;
yRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
yRotation.fromValue = [NSNumber numberWithFloat:0.0];
yRotation.toValue = [NSNumber numberWithFloat:y * angle * M_PI];

CABasicAnimation *zRotation;
zRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
zRotation.fromValue = [NSNumber numberWithFloat:0.0];
zRotation.toValue = [NSNumber numberWithFloat:z * angle * M_PI];

CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
groupAnimation.duration = t;
groupAnimation.removedOnCompletion = NO;
groupAnimation.fillMode = kCAFillModeForwards;
groupAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
groupAnimation.animations = [NSArray arrayWithObjects:moveAnimation, xRotation, yRotation, zRotation, nil];

[myCard addAnimation:groupAnimation forKey:@"animateCard"];
¿Fue útil?

Solución

Creo que lo que quiere en este caso es utilizar una ruta de acceso clave de ayuda como se describe en esta respuesta :

CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI];
rotationAnimation.duration = duration;
[myCard.layer addAnimation:rotationAnimation forKey:@"rotationAnimation1"];

que debe girar alrededor del eje X para la primera etapa de la animación. Para el segundo, creo que si se utiliza el siguiente

CABasicAnimation *rotationAnimation2 = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
rotationAnimation2.toValue = [NSNumber numberWithFloat: M_PI];
rotationAnimation2.duration = duration2;
rotationAnimation2.cumulative = YES;
[myCard.layer addAnimation:rotationAnimation2 forKey:@"rotationAnimation2"];

Se debe hacer las animaciones acumulativa y puede producir el efecto deseado. No he probado esto por mí mismo, por lo que algunos retoques puede ser necesaria para obtener el resultado que necesita exacta.

Cuando se está trabajando con una transformación directa, Core Animation interpola la transformación del valor actual de la transformación especificada. Se encontrará el camino más corto para llegar a esa transformación, lo que restringirá la dirección de animación. Si intenta animar la misma propiedad de transformar el doble, el segundo valor simplemente anular la primera, no se combinan las dos transformadas juntos.

Sin embargo, cuando se utiliza una ruta de acceso clave de ayuda de este tipo, Core Animation se interpolar entre el ángulo inicial y el ángulo final, por lo que puede invertir la dirección cambiando el signo del ángulo final. Optimiza el cambio en el valor de ángulo, no el cambio en el subyacente a transformar. También debe ser capaz de combinar animaciones en la ruta de acceso clave, porque la transformación se genera para usted bajo el capó para cada combinación de manipulaciones ruta de acceso clave.

Otros consejos

supongo el mover de un tirón en un eje es causada por bloqueo de ejes sucediendo dentro de la biblioteca de Apple. La solución fácil que funciona 99,999% de las veces es simplemente no uso exacto 0, 90, 180, 270, y 360 rotaciones grado. He visto cosas como esto suceda en mi código, pero sólo tiene que utilizar algo así como (M_PI * 0.99) en lugar de M_PI. Esto es siempre un problema si está utilizando multiplicadores de la matriz de la tarjeta de vídeo con ángulos de Euler.

Para aplicar varias transformaciones, al mismo tiempo, puede anidar ellos. Esto funciona exactamente igual que la multiplicación de matrices en OpenGL.

// translate and scale at the same time
float scale = 1.6;
CATransform3D scaleMatrix = CATransform3DMakeScale(scale, scale, 1);
CATransform3D finalMatrix = CATransform3DTranslate(scaleMatrix, frame.size.width/scale, frame.size.height/scale, 0);
CABasicAnimation* animBottomTrans = [CABasicAnimation animationWithKeyPath:@"transform"];
[animBottomTrans setFromValue:[NSValue valueWithCATransform3D:finalMatrix]];
[animBottomTrans setToValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]];
[animBottomTrans setDuration:duration];
[myLayer addAnimation:animBottomTrans forKey:@"transform"];

Recuerde que, dado que éstos están anidados que tiene que hacer frente a la anterior transformarse en cualquier transformación que vienen después de ella. En este código tengo que cambiar la cantidad traduje porque ya he escalado. Si se gira 90 grados en el eje Z y luego gira 90 grados sobre el eje y, que haya efectivamente acaba de girar en la Z y X ejes (la rotación z intercambia su x y ejes Y).

El resultante transformada es el mismo: (CGAffineTransform){-1,0,0,-1,0,0}. CoreAnimation recoge la rotación más corta que va a hacer el truco, y por defecto girando en sentido horario (creo).

La forma más fácil de girar la otra manera es rotar por casi -M_PI (no estoy seguro exactamente lo cerca que se puede conseguir antes de que decida hacer girar la forma "errónea").

La forma más complicada es dividirla en dos rotaciones: uno de 0 a -M_PI / 2 y uno de -M_PI / 2 a -M-PI. Creo que se puede programar un retardo de animación para que esto suceda ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top