Search code examples
iphoneiosios6core-animationcatransform3d

Perspective issue in 3D Rotation


I want to achieve something like this:

enter image description here

Which is a snapshot of my view controller

The code I have tried is like this:

    UIWindow *window = [[UIApplication sharedApplication] keyWindow];

    // Take a snapshot
    //
    _screenshotView = [[UIImageView alloc] initWithFrame:CGRectNull];

    _screenshotView.image = [self getScreenSnapshot];

    _screenshotView.frame = CGRectMake(-160, -284, _screenshotView.image.size.width, _screenshotView.image.size.height);
    _screenshotView.userInteractionEnabled = YES;
    _screenshotView.layer.anchorPoint = CGPointMake(0, 0);

    _originalSize = _screenshotView.frame.size;

    [window addSubview:_screenshotView];

    [self minimizeFromRect:CGRectMake(0, 0, _originalSize.width, _originalSize.height)];


- (void)minimizeFromRect:(CGRect)rect
{
    UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    CGFloat m = 0.7;
    CGFloat newWidth = _originalSize.width * m;
    CGFloat newHeight = _originalSize.height * m;

    [CATransaction begin];
    [CATransaction setValue:[NSNumber numberWithFloat:0.6] forKey:kCATransactionAnimationDuration];
    [self addAnimation:@"position.x" view:_screenshotView startValue:rect.origin.x endValue:window.frame.size.width - 80.0];
    [self addAnimation:@"position.y" view:_screenshotView startValue:rect.origin.y endValue:(window.frame.size.height - newHeight) / 2.0];
    [self addAnimation:@"bounds.size.width" view:_screenshotView startValue:rect.size.width endValue:newWidth];
    [self addAnimation:@"bounds.size.height" view:_screenshotView startValue:rect.size.height endValue:newHeight];

    _screenshotView.layer.position = CGPointMake(window.frame.size.width - 80.0, (window.frame.size.height - newHeight) / 2.0);
    _screenshotView.layer.bounds = CGRectMake(window.frame.size.width - 80.0, (window.frame.size.height - newHeight) / 2.0, newWidth, newHeight);

    CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
    rotationAndPerspectiveTransform.m34 = 1.0 / -600;
    rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, -20.0f * M_PI / 180.0f, 0.0f, 1.0f, 0.0f);
    _screenshotView.layer.transform = rotationAndPerspectiveTransform;

    [CATransaction commit];
}

The code works fine except that it looks like the rotation is shown from a different perspective because the snapshot after animation turns out to be like this:

enter image description here

What am I missing?


Solution

  • Solved by replacing UIImageView object with CALayer image layer object. Thanks to https://github.com/kristopherjohnson/perspectivetest

        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    
        // Take a snapshot
        //
    
        UIImage *image = [self getScreenSnapshot];
        CGImageRef pictureImage = image.CGImage;
    
        CGFloat zDistance = 1200.0f;
        CATransform3D transform = CATransform3DIdentity;
        transform.m34 = 1.0f / -zDistance;
    
        _screenshotView = [[UIView alloc] initWithFrame:CGRectNull];
        _screenshotView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
        _screenshotView.userInteractionEnabled = YES;
    
        _imageLayer = [CALayer layer];
        _imageLayer.frame = _screenshotView.frame;;
        _imageLayer.contents = (__bridge id)pictureImage;
        _imageLayer.transform = transform;
    
        [_screenshotView.layer addSublayer:_imageLayer];
    
        _originalSize = _screenshotView.frame.size;
    
        [window addSubview:_screenshotView];
    
        [self minimizeFromRect:CGRectMake(0, 0, _originalSize.width, _originalSize.height)];
    
    
    - (void)minimizeFromRect:(CGRect)rect
    {
        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
        CGFloat m = 0.6;
        CGFloat newWidth = _originalSize.width * m;
        CGFloat newHeight = _originalSize.height * m;
    
        [CATransaction begin];
        [CATransaction setValue:[NSNumber numberWithFloat:0.4] forKey:kCATransactionAnimationDuration];
        [self addAnimation:@"position.x" view:_screenshotView startValue:rect.origin.x endValue:window.frame.size.width - 40.0];
        [self addAnimation:@"position.y" view:_screenshotView startValue:rect.origin.y endValue:(window.frame.size.height - newHeight) / 2.0];
        [self addAnimation:@"bounds.size.width" view:_screenshotView startValue:rect.size.width endValue:newWidth];
        [self addAnimation:@"bounds.size.height" view:_screenshotView startValue:rect.size.height endValue:newHeight];
        [self addAnimationForLayer:@"transform.rotation.y" view:_imageLayer startValue:0.0f endValue:-0.4 * M_PI];
    
    
        _screenshotView.layer.position = CGPointMake(window.frame.size.width - 80.0, (window.frame.size.height - newHeight) / 2.0);
        _screenshotView.layer.bounds = CGRectMake(window.frame.size.width - 80.0, (window.frame.size.height - newHeight) / 2.0, newWidth, newHeight);
    
        [CATransaction commit];
    }