Question

Je travaille avec une animation de base pour la première fois et dans le processus de mise en œuvre d'une carte de jeu que je peux retourner autour, je l'ai décidé d'utiliser un CALayer pour afficher le contenu (ne sais pas comment je vais pour obtenir deux côtés, mais c'est une autre question) et je dois pouvoir la retourner, déplacer, etc ...

J'utilise CATransaction avec un certain succès - dans l'extrait ci-dessous, la carte se déplace du bas à gauche vers le haut à gauche et flips plus. Le problème est que je wan't à retourner le chemin opposé, mais je ne sais pas comment dire cela, « hey, vous allez dans le mauvais sens! »


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

Une deuxième question serait la suivante: comment puis-je à faire deux à la fois des transformations? J'ai essayé deux nicher CATransactions, mais le second prévaut sur seulement la première. J'ai aussi essayé de changer le vecteur de la rotation à 2D, comme dire à tourner autour des axes x et y, mais ce n'est pas équivalent à un peu renversant par pi autour de deux axes individuels. Voici le code imbriqué.


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

Et ici il est avec des blocs d'animation UIView à l'intérieur ... J'ai ajouté des curseurs pour l'angle, x, y, z pour le vecteur de rotation, et pour le temps t. La traduction se déroule au fil du temps = 2t et chacune des rotations devrait prendre juste t chacun.

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

Et voici où je suis maintenant: Tout fonctionne à une exception près. La rotation de revers (y commence à tourner dans le sens opposé) lorsque la carte arrive à pi / 2 et 3 pi / 2 *. Il retourne également autour de l'axe x à ces points. Mais x et z travail grand. Si proche!

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"];
Était-ce utile?

La solution

Je crois que ce que vous voulez dans ce cas est d'utiliser un keypath d'aide comme cela est décrit dans cette réponse :

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

qui devrait tourner autour de l'axe X pour la première étape de votre animation. Pour la deuxième, je crois que si vous utilisez les éléments suivants

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"];

il devrait rendre les animations cumulatifs et peut produire l'effet désiré. Je ne l'ai pas essayé moi-même, de sorte que certains bricolages peut être nécessaire pour obtenir le résultat exact dont vous avez besoin.

Lorsque vous travaillez avec une transformation directement, Core Animation interpole la transformation de la valeur actuelle à la transformation spécifiée. Il trouvera le chemin le plus court pour arriver à ce transform, ce qui limitera la direction d'animation. Si vous essayez d'animer la même transformer deux fois la propriété, la deuxième valeur simplement remplacer la première, ne pas combiner les deux transformations ensemble.

Cependant, lorsque vous utilisez un keypath d'aide comme celui-ci, Core Animation interpole entre votre angle de départ et l'angle de fin, de sorte que vous pouvez inverser la direction en changeant le signe de l'angle de fin. Il optimise la variation de valeur d'angle, pas le changement dans la transformation sous-jacente. Vous devriez être en mesure de combiner aussi des animations sur le keypath, car la transformation est généré pour vous sous le capot pour chaque combinaison de manipulations de KeyPath.

Autres conseils

Je devine que le basculement sur un axe est causé par blocage Cardan passe à l'intérieur de la bibliothèque d'Apple. La solution facile qui fonctionne 99,999% du temps est tout simplement pas utiliser exactement 0, 90, 180, 270 et 360 tours de degré. Je l'ai vu des choses comme cela arrive dans mon code, mais je viens d'utiliser quelque chose comme (M_PI * 0,99) au lieu de M_PI. Ceci est toujours un problème si vous utilisez les multiplicateurs de la matrice de carte vidéo avec des angles euler.

Pour appliquer plusieurs transformations en même temps, vous pouvez imbriquer. Cela fonctionne exactement comme la multiplication des 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"];

Rappelez-vous que puisque ceux-ci sont imbriquées, vous devez faire face à la précédente transformer en toute transformation qui viennent après. Dans ce code, je dois changer le montant que je traduis parce que je l'ai déjà mis à l'échelle. Si vous faites pivoter sur 90 degrés de l'axe z, puis faites pivoter de 90 degrés sur l'axe y, vous avez effectivement juste tourné le z et x axises (swaps rotation z votre x et y axises).

Le résultat de transformation est le même: (CGAffineTransform){-1,0,0,-1,0,0}. CoreAnimation choisit la rotation le plus court qui fera l'affaire, et par défaut de rotation dans le sens horaire (je pense).

La meilleure façon de tourner dans l'autre sens est de faire tourner par presque -M_PI (Je ne sais pas exactement à quel point vous pouvez obtenir avant de décider de faire tourner la « mauvaise »).

La façon plus complexe consiste à diviser en deux rotations: une de 0 à -M_PI / 2 et un de -M_PI / 2 -M-PI. Je pense que vous pouvez définir un délai d'animation pour y arriver ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top