How to flip a UIView around the x-axis while simultaneously switching subviews

Michael Gaylord picture Michael Gaylord · Mar 11, 2012 · Viewed 10.9k times · Source

This question has been asked before but in a slightly different way and I was unable to get any of the answers to work the way I wanted, so I am hoping somebody with great Core Animation skills can help me out.

I have a set of cards on a table. As the user swipes up or down the set of cards move up and down the table. There are 4 cards visible on the screen at any given time, but only the second card is showing its face. As the user swipes the second card flips back onto its face and the next card (depending on the swipe direction) lands in it's place showing its face.

I have set up my card view class like this:

@interface WLCard : UIView {
    UIView *_frontView;
    UIView *_backView;
    BOOL flipped;
}

And I have tried flipping the card using this piece of code:

- (void) flipCard {
    [self.flipTimer invalidate];
    if (flipped){
        return;
    }

    id animationsBlock = ^{
            self.backView.alpha = 1.0f;
            self.frontView.alpha = 0.0f;
            [self bringSubviewToFront:self.frontView];
            flipped = YES;

            CALayer *layer = self.layer;
            CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
            rotationAndPerspectiveTransform.m34 = 1.0 / 500;
            rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, M_PI, 1.0f, 0.0f, 0.0f);
            layer.transform = rotationAndPerspectiveTransform;
    };
    [UIView animateWithDuration:0.25
                          delay:0.0
                        options: UIViewAnimationCurveEaseInOut
                     animations:animationsBlock
                     completion:nil];

}

This code works but it has the following problems with it that I can't seem to figure out:

  1. Only half of the card across the x-axis is animated.
  2. Once flipped, the face of the card is upside down and mirrored.
  3. Once I've flipped the card I cannot get the animation to ever run again. In other words, I can run the animation block as many times as I want, but only the first time will animate. The subsequent times I try to animate lead to just a fade in and out between the subviews.

Also, bear in mind that I need to be able to interact with the face of the card. i.e. it has buttons on it.

If anybody has run into these issues it would be great to see your solutions. Even better would be to add a perspective transform to the animation to give it that extra bit of realism.

Answer

Michael Gaylord picture Michael Gaylord · Mar 12, 2012

This turned out to be way simpler than I thought and I didn't have to use any CoreAnimation libraries to achieve the effect. Thanks to @Aaron Hayman for the clue. I used transitionWithView:duration:options:animations:completion

My implementation inside the container view:

    [UIView transitionWithView:self 
                      duration:0.2 
                       options:UIViewAnimationOptionTransitionFlipFromBottom
                    animations: ^{
                            [self.backView removeFromSuperview];
                            [self addSubview:self.frontView];
                    }
                    completion:NULL];

The trick was the UIViewAnimationOptionTransitionFlipFromBottom option. Incidentally, Apple has this exact bit of code in their documentation. You can also add other animations to the block like resizing and moving.