You can write a gesture recognizer that does the transform
for you. For example, assuming you're able to flip both left and right, you could do something like the following. But the idea is that you transform the current view if you're less than half way through the flip, and transform the next view if more than half way through it:
- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
static UIView *currentView;
static UIView *previousView;
static UIView *nextView;
if (gesture.state == UIGestureRecognizerStateBegan)
{
// Set the three view variables here, based upon the logic of your app.
// If there is no `previousView` or `nextView`, then set them to `nil`
// as appropriate.
// I happen to be choosing views for child view controllers for my
// custom container, but I'll spare you that in case you're not using
// custom container controller.
}
// lets set the "percent" rotated as the percent across the screen the user's
// finger has travelled
CGPoint translation = [gesture translationInView:gesture.view.superview];
CGFloat percent = translation.x / gesture.view.frame.size.width;
CGFloat rotationPercent = percent;
// let's use the var to keep track of which view will be rotated
UIView *viewToTransform = nil;
if (percent < -0.5 && nextView)
{
// if user has moved finger more than half way across the screen to
// the left, and there is a `nextView`, then we're showing the second
// half of flip to the next screen
currentView.hidden = YES;
nextView.hidden = NO;
previousView.hidden = YES;
rotationPercent += 1.0;
viewToTransform = nextView;
}
else if (percent > 0.5 && previousView)
{
// if user has moved finger more than half way across the screen to
// the right, and there is a `previousView`, then we're showing the second
// half of flip to the previous screen
currentView.hidden = YES;
nextView.hidden = YES;
previousView.hidden = NO;
rotationPercent -= 1.0;
viewToTransform = previousView;
}
else if ((percent < 0 && nextView) || (percent > 0 && previousView))
{
// otherwise we're in the first half of the flip animation, so we're
// showing the `currentView`
currentView.hidden = NO;
nextView.hidden = YES;
previousView.hidden = YES;
viewToTransform = currentView;
}
// do the flip `transform`
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / -800;
viewToTransform.layer.transform = CATransform3DRotate(transform, M_PI * rotationPercent, 0.0, 1.0, 0.0);
// if we're all done, let's animate the completion (or if we didn't move far enough,
// the reversal) of the pan gesture
if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateCancelled ||
gesture.state == UIGestureRecognizerStateFailed)
{
// I'm personally using an index of my custom container child views, so I'm
// just updating my index appropriately; your logic may obviously differ
// here.
if (percent < -0.5 && nextView)
self.currentChildIndex++;
else if (percent > 0.5 && previousView)
self.currentChildIndex--;
// and animate the completion of the flip animation
[UIView animateWithDuration:0.25
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
previousView.transform = CGAffineTransformIdentity;
currentView.transform = CGAffineTransformIdentity;
nextView.transform = CGAffineTransformIdentity;
}
completion:NULL];
}
}