How to rotate a flat object around its center in perspective view?

后端 未结 2 1109
刺人心
刺人心 2020-12-12 13:14

What I\'m trying to do seems like it should be easy enough: I created a 2D top-down view of an old phonograph record. I want to rotate it (lay it back) in its X axis and th

相关标签:
2条回答
  • 2020-12-12 13:48

    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:

    spinning disc

    UPDATE

    Here's a Swift playground demonstration:

    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)
    

    Copy the image from the question into the playground Resources folder and name it 3DgoldRecord.png. Result:

    0 讨论(0)
  • 2020-12-12 13:53

    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.

    0 讨论(0)
提交回复
热议问题