我第一次使用Core Animation并且在实现可以翻转的扑克牌的过程中,我决定使用CALayer
来显示内容(不知道如何我会得到两个方面,但这是另一个问题)我需要能够翻转它,移动它等等......
我正在使用CATransaction
取得一些成功 - 在下面的片段中,卡片从左下角移动到左上角并翻转。问题是,我不想以相反的方式翻转,但不知道该怎么说,“嘿,你的方向错了!”
[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];
第二个问题是:如何让它一次完成两次变换?我已经尝试嵌套两个CATransactions
,但第二个只是覆盖了第一个。我也尝试将旋转的矢量更改为2D,就像说围绕x和y轴旋转一样,但这并不等于只用两个单独的轴来翻转它。这是嵌套代码。
[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];
这里有UIView
个动画块...我为角度添加了滑块,为旋转矢量添加了x,y,z,为时间添加了t。翻译在时间= 2t内进行,每次旋转每次只需要t。
[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];
这就是我现在所处的位置:一切都有一个例外。当卡达到pi / 2和3 * pi / 2时,y旋转反转(开始沿相反方向旋转)。它也会在这些点处绕x轴翻转。但x和z效果很好。太近了!
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"];
答案 0 :(得分:10)
我相信在这种情况下你想要的是使用像this answer中描述的帮助键路径:
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI];
rotationAnimation.duration = duration;
[myCard.layer addAnimation:rotationAnimation forKey:@"rotationAnimation1"];
应围绕X轴旋转动画的第一阶段。对于第二个,我相信如果您使用以下
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"];
它应该使动画累积并可能产生预期的效果。我自己没试过,所以可能需要一些修补才能得到你需要的确切结果。
当您直接使用变换时,Core Animation会将变换从当前值插值到指定的变换。它将找到进入该变换的最短路径,这将限制动画方向。如果您尝试对同一个转换属性设置两次动画,则第二个值将简单地覆盖第一个,而不是将两个转换组合在一起。
但是,当使用这样的辅助键路径时,Core Animation将在起始角度和结束角度之间进行插值,因此您可以通过更改结束角度的符号来反转方向。它优化了角度值的变化,而不是底层变换的变化。您还应该能够在键路径上组合动画,因为对于每个组合键路径操作,都会为您生成转换。
答案 1 :(得分:3)
我猜测在轴上的翻转是由Apple库中发生的万向节锁定引起的。 99.999%的时间工作的简单修复就是不使用精确的0度,90度,180度,270度和360度旋转。我已经看到过这样的事情发生在我的代码中,但我只是使用(M_PI * 0.99)而不是M_PI。如果您使用带有欧拉角的视频卡矩阵乘法器,这一直是个问题。
要同时应用多个变换,您可以嵌套它们。这与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"];
请记住,由于这些是嵌套的,因此您必须在其后的任何变换中处理先前的变换。在这段代码中,我必须更改我翻译的数量,因为我已经缩放了。如果在z轴上旋转90度,然后在y轴上旋转90度,则实际上只是在z轴和x轴上旋转(z旋转交换x轴和y轴)。
答案 2 :(得分:1)
结果变换是相同的:(CGAffineTransform){-1,0,0,-1,0,0}
。 CoreAnimation选择最短的旋转来完成这个技巧,并默认顺时针旋转(我认为)。
旋转另一种方式的最简单方法是按几乎 -M_PI
进行旋转(我不确定在它决定以“错误”的方式旋转之前你到底有多接近)。
更复杂的方法是将其分解为两个旋转:一个从0到-M_PI / 2,一个从-M_PI / 2到-M-PI。我认为你可以设置动画延迟来实现这一点......