简体   繁体   中英

UIView Flip Animation with Core Animation

Dear Core Animation/iOS Experts,

I am trying to get an effect similar to the question below.

Core animation animating the layer to flip horizontally

The accepted answer seems to describe exactly what I require, except there is no code with this answer and I can't get any code I write to work.

Here is exactly what I'm trying to do:
1) Have 1 master view controller/view and on a portion of the main view have 2 UIViews which overlap, with only one shown (1 at the 'front' and 1 at the 'back')
2) A separate UIControl/UIButton gets pressed and then a 3D flip transition occurs which rotates the front (visible) view out of view and at same time rotates the back (hidden) view to the front...just like seeing the reverse of a playing card.
3) Be able to keep pressing the UIControl to toggle between the two views
4) Be able to interact with just the controls on the front view (ie pressing the front layer won't inadvertently fire a control on the back which happens to lie underneath the tap)

I may be approaching this the wrong way so let me know. Ideally, I would like to use Core Animation, and not the UIView built in flip transactions, as I want the animation to be 3D and also want to use this task as a stepping stone for doing more complex CA stuff.

At the moment I can get the front view to flip nicely (only once) but the back view doesn't show.

Cheers,
Andy

Here is the code I've got:

MainViewController.h

@interface MainViewController : UIViewController
    - (IBAction)changeViewTapped:(UITapGestureRecognizer *)recognizer;
@end

MainViewController.m

#import "MainViewController.h"
#import <QuartzCore/QuartzCore.h>

@interface MainViewController ()

@property (weak, nonatomic) IBOutlet UIView *detailView;
@property (weak, nonatomic) IBOutlet UIView *listView;
@property (nonatomic) CATransform3D rotationAndPerspectiveTransform;

@end

@implementation MainViewController

@synthesize detailView = _detailView;
@synthesize listView = _listView;
@synthesize rotationAndPerspectiveTransform = _rotationAndPerspectiveTransform;

- (void)viewDidLoad {
    [super viewDidLoad];

    CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
    rotationAndPerspectiveTransform.m34 = 1.0 / -500;
    rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, M_PI, 0.0f, 1.0f, 0.0f);
    self.rotationAndPerspectiveTransform = rotationAndPerspectiveTransform;

    CALayer *listLayer = self.listView.layer;
    listLayer.doubleSided = NO;
    listLayer.transform = self.rotationAndPerspectiveTransform;
}

- (IBAction)changeViewTapped:(UITapGestureRecognizer *)recognizer {
    CALayer *detailLayer = self.detailView.layer;
    CALayer *listLayer = self.listView.layer;

    detailLayer.doubleSided = NO;
    listLayer.doubleSided = NO;

    [UIView animateWithDuration:0.5 animations:^{
        detailLayer.transform = self.rotationAndPerspectiveTransform;
        listLayer.transform = self.rotationAndPerspectiveTransform;
    } completion:^(BOOL finished){
        // code to be executed when flip is completed
    }];
}

@end

A quick tip about the flip animation in iOS -- the system needs time to render the back view (the one that will be flipped to) before you start the flip animation. So if you try to change the contents of that view, and trigger off the flip animation in the same method, you will have problems.

To get around this, I've had success with code like this:

- (void)flipView {
   // Setup the view for the back side of the flip

   [self performSelector:@selector(performFlip) withObject:nil afterDelay: 0.1];
}

- (void)performFlip {
    [UIView transitionWithView: tileToFlip
                      duration: 0.5
                       options: UIViewAnimationOptionTransitionFlipFromLeft
                    animations:^{
                        // My flip specific code
                    }
                    completion:^(BOOL finished) {
                    }
     ];
}

In a nutshell, I'm setting everything up in the flipView method, returning control to iOS so it has time to do it's rendering, then kicking off the flipTile selector after a tenth of a second to do the actual animation.

Good luck!

- (void)perform
{
   UIViewController *src = (UIViewController *) self.sourceViewController;
   UIViewController *dst = (UIViewController *) self.destinationViewController;    

  [UIView beginAnimations:@"LeftFlip" context:nil];
  [UIView setAnimationDuration:0.8];
  [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
  [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft    forView:src.view.superview cache:YES];
  [UIView commitAnimations];

  [src presentViewController:dst animated:NO completion:nil];
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM