3D Animation - CABasicAnimation and CATransform3D giving gap between views
caanimation, catransform3d, ios, ios5, iphone
Solution
At last solved my problem, messed up with anchor point
- (UIImage *)screenShot: (UIView *) aView
{
// Arbitrarily masks to 40%. Use whatever level you like
UIGraphicsBeginImageContext(hostView.frame.size);
[aView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGContextSetRGBFillColor (UIGraphicsGetCurrentContext(), 0, 0, 0, 0.4f);
CGContextFillRect (UIGraphicsGetCurrentContext(), hostView.frame);
UIGraphicsEndImageContext();
return image;
}
- (CALayer *) createLayerFromView: (UIView *) aView transform: (CATransform3D) transform
{
CALayer *imageLayer = [CALayer layer];
imageLayer.anchorPoint = CGPointMake(1.0f, 1.0f);
imageLayer.frame = (CGRect){.size = hostView.frame.size};
imageLayer.transform = transform;
UIImage *shot = [self screenShot:aView];
imageLayer.contents = (__bridge id) shot.CGImage;
return imageLayer;
}
- (void)animationDidStart:(CAAnimation *)animation
{
// UIView *source = (UIView *) super.sourceViewController;
[source removeFromSuperview];
}
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
{
// UIView *dest = (UIView *) super.destinationViewController;
if (hostView !=nil) {
NSLog(@"hostView %@",hostView);
if (dest) {
[hostView addSubview:dest];
}
}
[transformationLayer removeFromSuperlayer];
if (delegate)
SAFE_PERFORM_WITH_ARG(delegate, @selector(segueDidComplete), nil);
}
-(void)animateWithDuration: (CGFloat) aDuration
{
CAAnimationGroup *group = [CAAnimationGroup animation];
group.delegate = self;
group.duration = aDuration;
CGFloat halfWidth = hostView.frame.size.width / 2.0f;
float multiplier = goesForward ? -1.0f : 1.0f;
CABasicAnimation *translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"];
translationX.toValue = [NSNumber numberWithFloat:multiplier * halfWidth];
CABasicAnimation *translationZ = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.z"];
translationZ.toValue = [NSNumber numberWithFloat:-halfWidth];
CABasicAnimation *rotationY = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"];
rotationY.toValue = [NSNumber numberWithFloat: multiplier * M_PI_2];
group.animations = [NSArray arrayWithObjects: rotationY, translationX, translationZ, nil];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[CATransaction flush];
[transformationLayer addAnimation:group forKey:kAnimationKey];
}
- (void) constructRotationLayer
{
// UIView *source = (UIView *) super.sourceViewController;
// UIView *dest = (UIView *) super.destinationViewController;
hostView = source.superview;
transformationLayer = [CALayer layer];
transformationLayer.frame = hostView.bounds;
transformationLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
CATransform3D sublayerTransform = CATransform3DIdentity;
sublayerTransform.m34 = 1.0 / -1000;
[transformationLayer setSublayerTransform:sublayerTransform];
[hostView.layer addSublayer:transformationLayer];
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 0);
[transformationLayer addSublayer:[self createLayerFromView:source transform:transform]];
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
if (!goesForward)
{
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0);
}
[transformationLayer addSublayer:[self createLayerFromView:dest transform:transform]];
}
- (void)perform
{
[self constructRotationLayer];
[self animateWithDuration:0.4f];
}
Problem
So,I am trying to implement an animation which is in this app http://itunes.apple.com/us/app/spg-mobile-app/id312306003?mt=8 which is in the first view I have implemented animation for flipping views and i am succeeded in animating one side and when i have given the reverse logic for reverse flipping, it is giving some gap between views here is my code ``` - (UIImage *)screenShot: (UIView *) aView { // Arbitrarily masks to 40%. Use whatever level you like UIGraphicsBeginImageContext(hostView.frame.size); [aView.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); CGContextSetRGBFillColor (UIGraphicsGetCurrentContext(), 0, 0, 0, 0.4f); CGContextFillRect (UIGraphicsGetCurrentContext(), hostView.frame); UIGraphicsEndImageContext(); return image; } - (CALayer *) createLayerFromView: (UIView *) aView transform: (CATransform3D) transform { CALayer *imageLayer = [CALayer layer]; imageLayer.anchorPoint = CGPointMake(1.0f, 1.0f); imageLayer.frame = (CGRect){.size = hostView.frame.size}; imageLayer.transform = transform; UIImage *shot = [self screenShot:aView]; imageLayer.contents = (__bridge id) shot.CGImage; return imageLayer; } - (void)animationDidStart:(CAAnimation *)animation { UIView *source = (UIView *) _source; [source removeFromSuperview]; } - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished { UITableView *dest = (UITableView *) destination; dest.frame = CGRectMake(160, 0, 160, 460); [hostView addSubview:dest]; [transformationLayer removeFromSuperlayer]; //if (delegate) //SAFE_PERFORM_WITH_ARG(delegate, @selector(segueDidComplete), nil); } -(void)animateWithDuration: (CGFloat) aDuration { goesForward=FALSE ; CAAnimationGroup *group = [CAAnimationGroup animation]; group.delegate = self; group.duration = aDuration; CGFloat halfWidth = hostView.frame.size.width; // 2.0f; float multiplier = goesForward ? -1.0f : 1.0f; CABasicAnimation *translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"]; translationX.toValue = [NSNumber numberWithFloat:multiplier * halfWidth]; CABasicAnimation *translationZ = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.z"]; translationZ.toValue = [NSNumber numberWithFloat:-200.0]; //halfWidth]; CABasicAnimation *rotationY = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"]; rotationY.toValue = [NSNumber numberWithFloat: multiplier * M_PI_2]; group.animations = [NSArray arrayWithObjects: rotationY, translationX, translationZ, nil]; group.fillMode = kCAFillModeForwards; group.removedOnCompletion = NO; [CATransaction flush]; [transformationLayer addAnimation:group forKey:kAnimationKey]; } - (void) constructRotationLayer { UIView *source = (UIView *) _source; UIView *dest = (UIView *) destination; hostView = [source superview]; // if ([hostView isKindOfClass:[UIWindow class]]) { // NSLog(@"I am window class"); // } transformationLayer = [CALayer layer]; transformationLayer.frame = hostView.bounds; //CGRectMake(40, 0, 280, 460); transformationLayer.anchorPoint = CGPointMake(0.5f, 0.5f); CATransform3D sublayerTransform = CATransform3DIdentity; sublayerTransform.m34 = 1.0 / -1000; [transformationLayer setSublayerTransform:sublayerTransform]; [hostView.layer addSublayer:transformationLayer]; CATransform3D transform = CATransform3DMakeTranslation(0, 0, 0); [transformationLayer addSublayer:[self createLayerFromView:source transform:CATransform3DRotate(transform, M_PI_2, 0, 0, 0)]]; transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0); transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0); if (!goesForward) { transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0); transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0); transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0); transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0); } [transformationLayer addSublayer:[self createLayerFromView:dest transform:transform]]; } - (void)perform { [self constructRotationLayer]; [self animateWithDuration:0.4f]; } ``` So, here i am calling perform method first and Here i have uploaded my total code Here This Code worked for me a bit but still getting some gap, the thing is the frame of the going view and coming view should be same ``` - (UIImage *)screenShot: (UIView *) aView { // Arbitrarily masks to 40%. Use whatever level you like UIGraphicsBeginImageContext(hostView.frame.size); [aView.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); CGContextSetRGBFillColor (UIGraphicsGetCurrentContext(), 0, 0, 0, 0.4f); CGContextFillRect (UIGraphicsGetCurrentContext(), hostView.frame); UIGraphicsEndImageContext(); return image; } - (CALayer *) createLayerFromView: (UIView *) aView transform: (CATransform3D) transform { CALayer *imageLayer = [CALayer layer]; imageLayer.anchorPoint = CGPointMake(1.0f, 1.0f); imageLayer.frame = (CGRect){.size = hostView.frame.size}; imageLayer.transform = transform; UIImage *shot = [self screenShot:aView]; imageLayer.contents = (__bridge id) shot.CGImage; return imageLayer; } - (void)animationDidStart:(CAAnimation *)animation { // UIView *source = (UIView *) super.sourceViewController; [source removeFromSuperview]; } - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished { // UIView *dest = (UIView *) super.destinationViewController; if (hostView !=nil) { NSLog(@"hostView %@",hostView); if (dest) { [hostView addSubview:dest]; } } [transformationLayer removeFromSuperlayer]; if (delegate) SAFE_PERFORM_WITH_ARG(delegate, @selector(segueDidComplete), nil); } -(void)animateWithDuration: (CGFloat) aDuration { CAAnimationGroup *group = [CAAnimationGroup animation]; group.delegate = self; group.duration = aDuration; CGFloat halfWidth = hostView.frame.size.width / 2.0f; float multiplier = goesForward ? -1.0f : 1.0f; CABasicAnimation *translationX = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.x"]; translationX.toValue = [NSNumber numberWithFloat:multiplier * halfWidth]; CABasicAnimation *translationZ = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.translation.z"]; translationZ.toValue = [NSNumber numberWithFloat:-halfWidth]; CABasicAnimation *rotationY = [CABasicAnimation animationWithKeyPath:@"sublayerTransform.rotation.y"]; rotationY.toValue = [NSNumber numberWithFloat: multiplier * M_PI_2]; group.animations = [NSArray arrayWithObjects: rotationY, translationX, translationZ, nil]; group.fillMode = kCAFillModeForwards; group.removedOnCompletion = NO; [CATransaction flush]; [transformationLayer addAnimation:group forKey:kAnimationKey]; } - (void) constructRotationLayer { // UIView *source = (UIView *) super.sourceViewController; // UIView *dest = (UIView *) super.destinationViewController; hostView = source.superview; transformationLayer = [CALayer layer]; transformationLayer.frame = hostView.bounds; transformationLayer.anchorPoint = CGPointMake(0.5f, 0.5f); CATransform3D sublayerTransform = CATransform3DIdentity; sublayerTransform.m34 = 1.0 / -1000; [transformationLayer setSublayerTransform:sublayerTransform]; [hostView.layer addSublayer:transformationLayer]; CATransform3D transform = CATransform3DMakeTranslation(0, 0, 0); [transformationLayer addSublayer:[self createLayerFromView:source transform:transform]]; transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0); transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0); if (!goesForward) { transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0); transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0); transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0); transform = CATransform3DTranslate(transform, hostView.frame.size.width, 0, 0); } [transformationLayer addSublayer:[self createLayerFromView:dest transform:transform]]; } - (void)perform { [self constructRotationLayer]; [self animateWithDuration:0.4f]; } ```