如何使CATransform3dMakeRotation以其他方式旋转? 并链在一起

我第一次使用一些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"]; 

我相信在这种情况下你想要的是使用一个帮助键路径,就像在这个答案中描述的那样:

 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将在起始角度和结束角度之间进行插值,因此您可以通过更改结束角度的符号来反转方向。 它优化了角度值的变化,而不是底层变换的变化。 您还应该能够在键路径上组合动画,因为对于每个组合键路径操作,都会为您生成转换。

我猜测在轴上的翻转是由Apple库中发生的万向节锁定引起的。 99.999%的时间工作的简单修复就是不使用精确的0度,90度,180度,270度和360度旋转。 我在我的代码中看到过这样的事情,但我只是使用类似(M_PI * 0.99)而不是M_PI的东西。 如果您使用带有欧拉角的video卡矩阵乘数,这一直是个问题。

要同时应用多个变换,可以嵌套它们。 这与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轴)。

结果变换是相同的: (CGAffineTransform){-1,0,0,-1,0,0} 。 CoreAnimation选择最短的旋转来完成这个技巧,并默认顺时针旋转(我认为)。

旋转另一种方式的最简单方法是旋转几乎 -M_PI (我不确定在它决定旋转“错误”方式之前你能得到多少接近)。

更复杂的方法是将其分解为两个旋转:一个从0到-M_PI / 2,一个从-M_PI / 2到-M-PI。 我想你可以设置动画延迟来实现这一目标……