title: 3D Animation - CABasicAnimation and CATransform3D giving gap between views
body: <p>So,I am trying to implement an animation which is in this app <a href="http://itunes.apple.com/us/app/spg-mobile-app/id312306003?mt=8" rel="nofollow">http://itunes.apple.com/us/app/spg-mobile-app/id312306003?mt=8</a>  which is in the first view</p>
  
  <p>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</p>
  
  <p>here is my code</p>
  
  <pre><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];
  }
  </code></pre>
  
  <p>So, here i am calling perform method first
  and Here i have uploaded my total code <a href="http://dl.dropbox.com/u/75855691/FlipMe.zip" rel="nofollow">Here</a></p>
  
  <hr>
  
  <p>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</p>
  
  <pre><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 *) 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];
  }
  </code></pre>