Question

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?

Was it helpful?

Solution 2

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];
}

OTHER TIPS

One way around could be that you can use two images, one for upper half and one for lower half. And you can stitch the two images together so that the gap is not visible and you can get the desired output.

Set the property to one positive and one negative value for upper and one lower image or vice verse. You can get the two images of desired result. Then you can set the frame to make them stick together so that they look as one image.

Property :: rotationAndPerspectiveTransform.m34 = 1.0 / 600.0;

Property :: rotationAndPerspectiveTransform.m34 = -1.0 / 600.0;

You might need to do some hit and trial.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top