3

I'm trying to create a flip-and-scale animation between two view controllers. This seems possible using animation blocks available in iOS 4.0, but I'm still unsure how to implement it. I found this SO question which shows a flip animation.

Using this code, flipping between two views works fine, but scaling doesn't -- the flip animation completes and then the new view jumps to the correct size. How would I flip the view and scale it at the same time?

UIView *tempContainer = myView.contentView ;
[UIView transitionWithView:tempContainer
                  duration:2
                   options:UIViewAnimationOptionTransitionFlipFromRight
                animations:^{ 
                    [[[tempContainer subviews] objectAtIndex:0] removeFromSuperview]; 
                    [tempContainer addSubview:myOtherViewController.view];
                    CGAffineTransform transform = CGAffineTransformMakeScale(4.0, 4.0);
                    tempContainer.transform = transform;
                } 
                completion:^(BOOL finished){
                    [tempContainer release]; 
                }];
Community
  • 1
  • 1
memmons
  • 40,222
  • 21
  • 149
  • 183

2 Answers2

0

Here's how I flip and scale between two views of different sizes. I break the animation into a few parts. First I put the back view at the same location as the front view, but make it hidden. I then flip and scale the front view halfway. The back view is given the same transform as the front view, then rotated and scaled the rest of the way. Flipping back is basically the reverse.

I suppose you could use a different view controllers view property as the back view, but I haven't tried that.

// flip and scale frontView to reveal backView to the center of the screen
// uses a containerView to mark the end of the animation
// parameterizing the destination is an exercise for the reader
- (void)flipFromFront:(UIView*)frontView toBack:(UIView*)backView destination:(CGRect)destRect
{
    float duration = 0.5;

    // distance from center of screen from frontView
    float dx = destRect.origin.x + CGRectGetWidth(destRect) / 2 - frontView.center.x;
    float dy = destRect.origin.y + CGRectGetHeight(destRect) / 2 - frontView.center.y;
    float scale = CGRectGetWidth(destRect) / CGRectGetWidth(frontView.bounds);

    // this prevents any tearing
    backView.layer.zPosition = 200.0;

    // hide the backView and position where frontView is
    backView.hidden = NO;
    backView.alpha = 0.0;
    backView.frame = frontView.frame;

    // start the animation
    [UIView animateKeyframesWithDuration:duration
                                   delay:0.25
                                 options:UIViewKeyframeAnimationOptionCalculationModeCubic
                              animations:^{
                                  // part 1.  Rotate and scale frontView halfWay.
                                  [UIView addKeyframeWithRelativeStartTime:0.0
                                                          relativeDuration:0.5
                                                                animations:^{
                                                                    // get the transform for the blue layer
                                                                    CATransform3D xform = frontView.layer.transform;
                                                                    // translate half way
                                                                    xform = CATransform3DTranslate(xform, dx/2, dy/2, 0);
                                                                    // rotate half way
                                                                    xform = CATransform3DRotate(xform, M_PI_2, 0, 1, 0);
                                                                    // scale half way
                                                                    xform = CATransform3DScale(xform, scale/2, scale/2, 1);
                                                                    // apply the transform
                                                                    frontView.layer.transform = xform;
                                                                }];

                                  // part 2. set the backView transform to frontView so they are in the same
                                  // position.
                                  [UIView addKeyframeWithRelativeStartTime:0.5
                                                          relativeDuration:0.0
                                                                animations:^{
                                                                    backView.layer.transform = frontView.layer.transform;
                                                                    backView.alpha = 1.0;
                                                                }];

                                  // part 3.  rotate and scale backView into center of container
                                  [UIView addKeyframeWithRelativeStartTime:0.5
                                                          relativeDuration:0.5
                                                                animations:^{
                                                                    // undo previous transforms with animation
                                                                    backView.layer.transform = CATransform3DIdentity;
                                                                    // animate backView into new location
                                                                    backView.frame = destRect;
                                                                }];
                              } completion:^(BOOL finished) {
                                  self.displayingFront = !self.displayingFront;
                              }];
}

// flip from back to front
- (void) flipFromBack:(UIView*)backView toFront:(UIView*)frontView
{
    float duration = 0.5;

    // get distance from center of screen to destination
    float dx = backView.center.x - frontView.center.x;
    float dy = backView.center.y - frontView.center.y;

    backView.layer.zPosition = 200.0;
    frontView.hidden = YES;

    // this is basically the reverse of the previous animation
    [UIView animateKeyframesWithDuration:duration
                                   delay:0
                                 options:UIViewKeyframeAnimationOptionCalculationModeCubic
                              animations:^{
                                  [UIView addKeyframeWithRelativeStartTime:0.0
                                                          relativeDuration:0.5
                                                                animations:^{
                                                                    CATransform3D xform = backView.layer.transform;
                                                                    xform = CATransform3DTranslate(xform, -dx/2, -dy/2, 0);
                                                                    xform = CATransform3DRotate(xform, M_PI_2, 0, 1, 0);
                                                                    xform = CATransform3DScale(xform, 0.75, 0.75, 1);
                                                                    backView.layer.transform = xform;
                                                                }];

                                  [UIView addKeyframeWithRelativeStartTime:0.5
                                                          relativeDuration:0.0
                                                                animations:^{
                                                                    backView.alpha = 0.0;
                                                                    frontView.hidden = NO;
                                                                }];

                                  [UIView addKeyframeWithRelativeStartTime:0.5
                                                          relativeDuration:0.5
                                                                animations:^{
                                                                    self.hiddenView.alpha = 0.0;
                                                                    frontView.layer.transform = CATransform3DIdentity;
                                                                }];
                              } completion:^(BOOL finished) {
                                  self.displayingFront = !self.displayingFront;
                              }];
}
Former Gaucho
  • 141
  • 1
  • 4
0

I suppose this happens because the option UIViewAnimationOptionTransitionFlipFromRight somehow overrides everything else. Try using nesting animations or link them together

adubr
  • 779
  • 7
  • 21