Introduction
Ok, so maybe you need a page flip animation. There are lots of UIView default animations, that look really good, but my UI designed really busted me and was like "NO, I WANT A BARN DOOR FLIP". Anyway, there isn't a default way that I could find to do this. So I had to take a dive into core animation land and dig deep.
Flipping Open
Aight, so to flip a view open, we take the view, and rotate it using core animation by 90 degrees in y direction around the left side of it. All makes sense right? So, get a UIView as a container and add anything you want to flip onto it.
-(void)pageOpen { //Make sure the container is visible and remove any other previous animations from it [uiv_container.layer removeAllAnimations]; [uiv_front setHidden:NO]; [uiv_container setUserInteractionEnabled:NO]; //Sets the anchor point to the middle of the left side uiv_container.layer.anchorPoint = CGPointMake(0.0f,0.5f); //Set up a new animation to describe the transform CABasicAnimation *ba_animation = [CABasicAnimation animationWithKeyPath:@"transform"]; ba_animation.removedOnCompletion = NO; //This is the time it takes for the animation to complete, here its 2 seconds ba_animation.duration = 2.0; //Using different timing functions will change the animation speed at different points. Ex: kCAMediaTimingFunctionEaseIn ba_animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; //Start from the identity matrix. If you haven't every done 3D programming, the Identity matrix is basically the normal matrix of anything ba_animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; //Set up the end matrix. Here we are setting it to 90 degrees in the Y direction CATransform3D t_end = CATransform3DMakeRotation(M_PI/2, 0.0, -1.0, 0.0); //This value controls the size of the end, modifying it like this makes it get bigger, making it more like a 3D rotation t_end.m14 = -0.001f; ba_animation.toValue = [NSValue valueWithCATransform3D:t_end]; //Add the animation to an animation group, this lets us track the animation as it finishes CAAnimationGroup *ag_group = [CAAnimationGroup animation]; ag_group.delegate = self; ag_group.duration = 2.0; [ag_group setValue:[NSNumber numberWithInt:1] forKey:@"Animation Tag"]; ag_group.animations = [NSArray arrayWithObjects:ba_animation, nil]; [uiv_container.layer addAnimation:ag_group forKey:@"Flip View"]; }
Flipping Closed
Now, we have the page up, so next we need to rotate it down back to flat. Rotate it another 90 degrees in the Y direction, this time we need to rotate on the right side of it (so all the text looks right when its rotating down. This gives the illusion that there is a front and a back to the view.
-(void)pageFlip { NSLog(@"page opening"); uiv_container.layer.anchorPoint = CGPointMake(1.0f,0.5f); CABasicAnimation *ba_animation = [CABasicAnimation animationWithKeyPath:@"transform"]; ba_animation.removedOnCompletion = NO; ba_animation.duration = 2.0; ba_animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; //This time we need to start from the position where the frame is 90 degrees rotated CATransform3D t_start = CATransform3DMakeRotation(M_PI/2, 0.0, -1.0, 0.0); //Need the opposite of the previous value so that the edge is sized correctly from the beginning t_start.m14 = 0.001f; ba_animation.fromValue = [NSValue valueWithCATransform3D:t_start]; //Now rotate it down to the identity matrix ba_animation.toValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; CAAnimationGroup *ag_group = [CAAnimationGroup animation]; ag_group.delegate = self; ag_group.duration = 2.0; [ag_group setValue:[NSNumber numberWithInt:2] forKey:@"Animation Tag"]; ag_group.animations = [NSArray arrayWithObjects:ba_animation, nil]; [uiv_container.layer addAnimation:ag_group forKey:@"Flip View"]; }
Animation Did Finish selector
Finally, we need something to manage everything when the animation ends. So here we tell it to run the the page flip after the page open finishes
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag { NSLog(@"animation did stop"); // Get the tag from the animation, we use it to find the // animated UIView NSNumber *tag = [theAnimation valueForKey:@"Animation Tag"]; if([tag intValue] == 1) { uiv_front.hidden = YES; [uiv_front removeFromSuperview]; [self.view addSubview:uiv_back]; uiv_back.hidden = NO; [self pageOpen]; } if([tag intValue] == 2) { } }