如何在透视图中围绕其中心旋转扁平物体?

我试图做的似乎应该很容易:我创build了一个旧的唱片logging的2D自上而下的视图。 我想旋转它(放回)在其X轴,然后围绕其Z轴旋转。

我已经阅读了这里有CATransform3D的所有问题,我已经阅读过Steve Baker的“matrix可以成为你的朋友”的文章以及Bill Dudney的书“Mac OS X和iPhone的核心animation”。我认为Brad Larson的“没有轨迹球的3-D旋转“具有所有正确的代码,但是由于他允许用户调整所有三个轴,我很难将他的代码缩小到我认为只是一个维度(旋转的z轴)。

这是我正在testing的图像,而不是详细信息对于这个问题很重要:

黄金纪录

我通常在屏幕上显示:(在UIView的子类中)

- (void)awakeFromNib { UIImage *recordImage = [UIImage imageNamed:@"3DgoldRecord"]; if (recordImage) { recordLayer = [CALayer layer]; [recordLayer setFrame:CGRectMake(0.0, 0.0, 1024, 1024)]; [recordLayer setContents:(id)[[UIImage imageNamed:@"3DgoldRecord"] CGImage]]; [self.layer addSublayer:recordLayer]; } } 

这是第一个testing,只是把它放在屏幕上;-)

然后,为了“放回原处”,我应用一个变换来绕图层的X轴旋转,在将图层的内容设置为图像之后并在添加子图层之前插入此代码:

  CATransform3D myRotationTransform = CATransform3DRotate(recordLayer.transform, (M_PI_2 * 0.85), //experiment with flatness 1.0, // rotate only across the x-axis 0.0, // no y-axis transform 0.0); // no z-axis transform recordLayer.transform = myRotationTransform; 

如预期的那样工作:logging很好地放下。

而下一步,导致logging旋转,我把这个animation绑定到touchesEnded事件,虽然一旦超出了testing/学习阶段,这个旋转将不会在用户控制之下:

 CATransform3D currentTransform = recordLayer.transform; // to come back to at the end CATransform3D myRotationTransform = CATransform3DRotate(currentTransform, 1.0, // go all the way around once (M_PI_2 * 0.85), // x-axis change 1.00, // y-axis change ? 0.0); // z-axis change ? recordLayer.transform = myRotationTransform; CABasicAnimation *myAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; myAnimation.duration = 5.0; myAnimation.fromValue = [NSNumber numberWithFloat:0.0]; myAnimation.toValue = [NSNumber numberWithFloat:M_PI * 2.0]; myAnimation.delegate = self; [recordLayer addAnimation:myAnimation forKey:@"transform.rotation"]; 

所以我很确定我所挂的是CATransform3DRotate调用中的vector(相信我:我一直在试图简单地改变这个vector来观察变化…现在列出的只是最后一个变化我试过了)。 据我所知,转换中x,y和z的值本质上是在从fromValue到toValue的animation范围内传入的值的百分比。

如果我在正确的轨道上了解这一点,是否有可能在一个单一的转换expression呢? 或者我必须对每个有效的animation帧,将原始的直立图像绕z轴旋转一下,然后将结果放在x轴旋转的位置? 我看到一个关于合并变换的问题/答案,但这是一个缩放变换,随后是旋转变换。 我已经搞砸了转换,但并没有做我认为我应该得到的(即将一个转换的结果传递给下一个的转换参数似乎只是完全执行一个,然后animation另一个)。

如果您使用CATransformLayer作为图像视图图层的父级,这是最简单的。 所以你需要一个使用CATransformLayer作为图层的自定义视图子类。 这是微不足道的:

 @interface TransformView : UIView @end @implementation TransformView + (Class)layerClass { return [CATransformLayer class]; } @end 

把一个TransformView放入你的笔尖,然后添加一个UIImageView作为TransformView的子视图。 将这些视图连接到视图控制器中名为transformViewdiscView

在视图控制器中,设置transformView的transformView以应用透视(通过设置m34 )和X轴倾斜:

 - (void)viewDidLoad { [super viewDidLoad]; CATransform3D transform = CATransform3DIdentity; transform.m34 = -1 / 500.0; transform = CATransform3DRotate(transform, .85 * M_PI_2, 1, 0, 0); self.transformView.layer.transform = transform; } 

将关键pathtransform.rotation.z的animation添加到viewWillAppear: discView中,并将其在viewDidDisappear:删除:

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; animation.fromValue = [NSNumber numberWithFloat:0]; animation.toValue = [NSNumber numberWithFloat:2 * M_PI]; animation.duration = 1.0; animation.repeatCount = HUGE_VALF; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; [self.discView.layer addAnimation:animation forKey:@"transform.rotation.z"]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self.discView.layer removeAllAnimations]; } 

结果:

旋转盘

UPDATE

这是一个Swift游乐场示范:

 import UIKit import XCPlayground class TransformView: UIView { override class func layerClass() -> AnyClass { return CATransformLayer.self } } let view = UIView(frame: CGRectMake(0, 0, 300, 150)) view.backgroundColor = UIColor.groupTableViewBackgroundColor() XCPlaygroundPage.currentPage.liveView = view let transformView = TransformView(frame: view.bounds) view.addSubview(transformView) var transform = CATransform3DIdentity transform.m34 = CGFloat(-1) / transformView.bounds.width transform = CATransform3DRotate(transform, 0.85 * CGFloat(M_PI_2), 1, 0, 0) transformView.layer.transform = transform let image = UIImage(named: "3DgoldRecord")! let imageView = UIImageView(image: image) imageView.bounds = CGRectMake(0, 0, 200, 200) imageView.center = CGPointMake(transformView.bounds.midX, transformView.bounds.midY) transformView.addSubview(imageView) let animation = CABasicAnimation(keyPath: "transform.rotation.z") animation.fromValue = 0 animation.toValue = 2 * M_PI animation.duration = 1 animation.repeatCount = Float.infinity animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) imageView.layer.addAnimation(animation, forKey: animation.keyPath) 

将问题中的图像复制到操场资源文件夹中,并命名为3DgoldRecord.png 。 结果:

操场结果

你可以考虑用superlayer包装recordlayer。 将x轴旋转应用于超级图层,并将z轴旋转animation添加到recordLayer。