4

I want to perform a flip animation when the user drags the finger from the right side of the screen. The state of the animation should be influenced by the length of the drag and shouldn't work automatically.

I used something like this:

if (transitionBegan) {

    flipTransition = CATransform3DIdentity;
    flipTransition.m34 = 1.0 / -500;
    flipTransition = CATransform3DRotate(flipTransition, degree * M_PI / 180.0f,0.0f, 1.0f, 0.0f);
    self.view.layer.transform = flipTransition;
}

But now I don't know how to realize the transition between my views, so that view A disappears and view B appears.

Can you help me?

schirrmacher
  • 2,341
  • 2
  • 27
  • 29
  • I assume you're talking about a flip that progresses (or stops) as the users' finger moves (or pauses). I think you need to pursue using a custom container in that situation, navigating with a `UIPanGestureRecognizer`. [This post](http://stackoverflow.com/questions/15703613/navigating-uiviewcontrollers-with-gestures-in-ios/15747892#15747892) shows how to do this with a push-style animation, but could be tweaked to do flip annotation, too. – Rob Apr 04 '13 at 21:26

3 Answers3

3

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];
    }
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Since iOS 7, you might use interactive custom transitions (see http://stackoverflow.com/a/10407713/1271826), using block-based UIView animations. I'll update this answer accordingly. – Rob Apr 01 '16 at 17:50
2

You should be able to do it with the help of a UIPanGestureRecognizer (Gesture recognizer that is listening on finger dragging), you'll be able to get the length of the Pan, and from there, calculate your CATransform3D-based translations and scalings following the progress of the panning.

(Built-in animations are not useful there, you have to make some use of CoreAnimation here, it's fun, I can tell you ;-))

Mathieu Amiot
  • 1,204
  • 8
  • 16
0

Use UIView animateWithDuration: animations: completion: method to animate the current view up to the transition point then in the completion block remove the current view, add the new view and start another similar animation on the new view.

Matti Jokipii
  • 561
  • 1
  • 6
  • 20