¿Cómo rotar una CATransform3dMakeRotation para el otro lado? Y cadena juntos

Estoy trabajando con Core Animation por primera vez y en el process de implementación de una tarjeta de juego que puedo voltear, he decidido usar un CALayer para mostrar los contenidos (no estoy seguro de cómo voy a get dos lados, pero esa es otra pregunta) y necesito poder voltearlo, moverlo, etc.

Estoy usando CATransaction con cierto éxito: en el fragment de abajo, la tarjeta se mueve desde la esquina inferior izquierda hasta la esquina superior izquierda y se voltea. El problema es que no quiero voltear de la manera opuesta, pero no sé cómo decirlo, "¡Oye, vas por el path 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 lograr que haga dos transformaciones a la vez? He intentado anidar dos CATransactions , pero el segundo anula el primero. También traté de cambiar el vector para que la rotation sea 2D, como decir que gira alnetworkingedor de ejes xy y, pero eso no es equivalente a simplemente voltearlo con pi alnetworkingedor de dos ejes individuales. Aquí está el código nested.


 [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í está con los bloques de animation UIView dentro … He agregado controles deslizantes para el ángulo, x, y, z para el vector de rotation, y t para el time. La traducción se realiza a lo largo del time = 2t y cada una de las rotaciones debe tomar solo t cada una.

 [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 exception. La rotation de y se invierte (comienza a girar en la dirección opuesta) cuando la carta llega a pi / 2 y 3 * pi / 2. También gira alnetworkingedor del eje x en estos puntos. Pero xy z funcionan de maravilla. ¡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"]; 

Creo que lo que quiere en este caso es utilizar una ruta de acceso del ayudante 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 debería rotar sobre el eje X para la primera etapa de tu animation. Por el segundo, creo que si usa lo 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"]; 

debería hacer que las animaciones sean acumulativas y producir el efecto deseado. No he intentado esto por mí mismo, por lo que puede requerir algunos retoques para get el resultado exacto que necesita.

Cuando esté trabajando con una transformación directamente, Core Animation interpolará la transformación del valor actual a la transformación especificada. Encontrará la ruta más corta para llegar a esa transformación, lo que restringirá la dirección de la animation. Si intenta animar la misma propiedad de transformación dos veces, el segundo valor simplemente anulará la primera, no combinará las dos transformadas juntas.

Sin embargo, al usar una ruta de acceso auxiliar como esta, Core Animation se interpolará entre su ángulo inicial y final, por lo que puede invertir la dirección cambiando el signo del ángulo final. Optimiza el cambio en el valor del ángulo, no el cambio en la transformación subyacente. También debería ser capaz de combinar animaciones en la ruta de acceso de keyboard, ya que la transformación se genera bajo el capó para cada combinación de manipulaciones de ruta de acceso de keyboard.

Supongo que el giro de un eje es causado por el locking del cardán que ocurre dentro de la biblioteca de Apple. La solución fácil que funciona 99.999% del time es simplemente no usar rotaciones exactas de 0, 90, 180, 270 y 360 grados. He visto cosas como esta suceden en mi código, pero simplemente uso algo como (M_PI * 0.99) en lugar de M_PI. Esto siempre es un problema si está utilizando los multiplicadores de matriz de la tarjeta de video con angularjs de Euler.

Para aplicar múltiples transformaciones al mismo time, puede anidarlas. Esto funciona exactamente como multiplicar 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"]; 

Restring que, dado que estos están nesteds, tienes que lidiar con la transformación anterior en cualquier transformación que se produzca después. En este código, debo cambiar la cantidad que traduje porque ya he escalado. Si gira 90 grados en el eje z y luego gira 90 grados en el eje y, simplemente ha girado efectivamente en los ejes z y x (la rotation z intercambia sus ejes x e y).

La transformación resultante es la misma: (CGAffineTransform){-1,0,0,-1,0,0} . CoreAnimation selecciona la rotation más corta que hará el truco, y por defecto girará en el sentido de las agujas del reloj (creo).

La forma más fácil de girar en sentido contrario es rotar casi en -M_PI (no estoy seguro de qué tan cerca se puede llegar antes de que decida rotar la forma "incorrecta").

La forma más complicada es dividirla en dos rotaciones: una de 0 a -M_PI / 2 y una de -M_PI / 2 a -M-PI. Creo que puedes configurar un retraso de animation para que esto suceda …