How to rotate a flat object around its center in perspective view?
This is easiest if you use a CATransformLayer
as the parent of the image view's layer. So you'll need a custom view subclass that uses CATransformLayer
as its layer. This is trivial:
@interface TransformView : UIView@end@implementation TransformView+ (Class)layerClass { return [CATransformLayer class];}@end
Put a TransformView
in your nib, and add a UIImageView
as a subview of the TransformView
. Connect these views to outlets in your view controller called transformView
and discView
.
In your view controller, set the transform of transformView
to apply perspective (by setting m34
) and the X-axis tilt:
- (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;}
Add an animation for key path transform.rotation.z
to discView
in viewWillAppear:
and remove it in 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];}
Result:
UPDATE
Here's a Swift playground demonstration:
import UIKitimport XCPlaygroundclass 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 = viewlet transformView = TransformView(frame: view.bounds)view.addSubview(transformView)var transform = CATransform3DIdentitytransform.m34 = CGFloat(-1) / transformView.bounds.widthtransform = CATransform3DRotate(transform, 0.85 * CGFloat(M_PI_2), 1, 0, 0)transformView.layer.transform = transformlet 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 = 0animation.toValue = 2 * M_PIanimation.duration = 1animation.repeatCount = Float.infinityanimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)imageView.layer.addAnimation(animation, forKey: animation.keyPath)
Copy the image from the question into the playground Resources folder and name it 3DgoldRecord.png
. Result:
You may consider wrapping the recordLayer with a superlayer. Apply the x-axis rotation to the superlayer and add the z-axis rotation animation to recordLayer.