Skip to content

Instantly share code, notes, and snippets.

@yberdnikov
Forked from visnup/SlideAnimatedTransitioning.h
Last active August 29, 2015 14:20
Show Gist options
  • Save yberdnikov/a9ec6adf9c70912fe94c to your computer and use it in GitHub Desktop.
Save yberdnikov/a9ec6adf9c70912fe94c to your computer and use it in GitHub Desktop.

Revisions

  1. @visnup visnup revised this gist Apr 17, 2014. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions ViewController.m
    Original file line number Diff line number Diff line change
    @@ -22,6 +22,7 @@ - (void)viewDidLoad
    {
    [super viewDidLoad];

    // Setup a screen edge pan gesture recognizer to trigger from the right edge of the screen.
    self.edgePanGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleScreenEdgePanGesture:)];
    self.edgePanGestureRecognizer.edges = UIRectEdgeRight;
    [self.view addGestureRecognizer:self.edgePanGestureRecognizer];
    @@ -34,13 +35,17 @@ - (void)handleScreenEdgePanGesture:(UIScreenEdgePanGestureRecognizer *)sender

    switch (sender.state) {
    case UIGestureRecognizerStateBegan:
    // Configure the navigation controller to return the custom (interactive/animated) transition.
    self.navigationController.delegate = self;
    // Trigger a segue (or push another view controller, whatevs you want).
    [self performSegueWithIdentifier:@"next" sender:sender];
    break;
    case UIGestureRecognizerStateChanged:
    // Update the transition using a UIPercentDrivenInteractiveTransition.
    [self.percentDrivenInteractiveTransition updateInteractiveTransition:percent];
    break;
    case UIGestureRecognizerStateEnded:
    // Cancel or finish depending on how the gesture ended.
    if (percent > 0.5 || fabs([sender velocityInView:self.view].x) > 1000)
    [self.percentDrivenInteractiveTransition finishInteractiveTransition];
    else
    @@ -53,11 +58,13 @@ - (void)handleScreenEdgePanGesture:(UIScreenEdgePanGestureRecognizer *)sender

    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
    {
    // Have to return a custom transition here in order for the navigation controller to ask about the interactive stuff below. The SlideAnimatedTransitioning just tries to duplicate the default transition as much as possible.
    return [SlideAnimatedTransitioning new];
    }

    - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
    {
    // Unset the delegate so that all other types of transitions (back, normal animated push not initiated by a gesture) get the default behavior.
    self.navigationController.delegate = nil;

    if (self.edgePanGestureRecognizer.state == UIGestureRecognizerStateBegan) {
  2. @visnup visnup revised this gist Apr 17, 2014. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions SlideAnimatedTransitioning.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    //
    // SlideAnimatedTransitioning.h
    // SwipeLeft
    //
    // Created by Visnu on 4/14/14.
    // Copyright (c) 2014 Visnu Pitiyanuvath. All rights reserved.
    //

    #import <Foundation/Foundation.h>

    @interface SlideAnimatedTransitioning : NSObject <UIViewControllerAnimatedTransitioning>

    @end
  3. @visnup visnup revised this gist Apr 17, 2014. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions SlideAnimatedTransitioning.m
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,15 @@
    //
    // SlideTransition.m
    // SlideAnimatedTransitioning.m
    // SwipeLeft
    //
    // Created by Visnu on 4/14/14.
    // Copyright (c) 2014 Visnu Pitiyanuvath. All rights reserved.
    //

    #import "SlideTransition.h"
    #import "SlideAnimatedTransitioning.h"

    // Tries to duplicate the default iOS 7 slide transition for UINavigationController
    @implementation SlideTransition
    @implementation SlideAnimatedTransitioning

    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
  4. @visnup visnup created this gist Apr 17, 2014.
    50 changes: 50 additions & 0 deletions SlideAnimatedTransitioning.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,50 @@
    //
    // SlideTransition.m
    // SwipeLeft
    //
    // Created by Visnu on 4/14/14.
    // Copyright (c) 2014 Visnu Pitiyanuvath. All rights reserved.
    //

    #import "SlideTransition.h"

    // Tries to duplicate the default iOS 7 slide transition for UINavigationController
    @implementation SlideTransition

    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
    UIView *containerView = [transitionContext containerView],
    *fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view,
    *toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;

    CGFloat width = containerView.frame.size.width;

    CGRect offsetLeft = fromView.frame; offsetLeft.origin.x = -width/3;

    CGRect offscreenRight = toView.frame; offscreenRight.origin.x = width;
    toView.frame = offscreenRight;
    toView.layer.shadowRadius = 5;
    toView.layer.shadowOpacity = 0.4;

    [containerView addSubview:toView];

    [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    toView.frame = fromView.frame;

    fromView.frame = offsetLeft;
    fromView.layer.opacity = 0.9;
    } completion:^(BOOL finished) {
    fromView.layer.opacity = 1;
    toView.layer.shadowOpacity = 0;
    // when cancelling or completing the animation, ios simulator seems to sometimes flash black backgrounds during the animation. on devices, this doesn't seem to happen though.
    // containerView.backgroundColor = [UIColor whiteColor];
    [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
    }

    - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
    {
    return 0.2;
    }

    @end
    73 changes: 73 additions & 0 deletions ViewController.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,73 @@
    //
    // ViewController.m
    // SwipeLeft
    //
    // Created by Visnu on 4/10/14.
    // Copyright (c) 2014 Visnu Pitiyanuvath. All rights reserved.
    //

    #import "ViewController.h"
    #import "SlideAnimatedTransitioning.h"

    @interface ViewController ()

    @property UIScreenEdgePanGestureRecognizer *edgePanGestureRecognizer;
    @property UIPercentDrivenInteractiveTransition *percentDrivenInteractiveTransition;

    @end

    @implementation ViewController

    - (void)viewDidLoad
    {
    [super viewDidLoad];

    self.edgePanGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleScreenEdgePanGesture:)];
    self.edgePanGestureRecognizer.edges = UIRectEdgeRight;
    [self.view addGestureRecognizer:self.edgePanGestureRecognizer];
    }

    - (void)handleScreenEdgePanGesture:(UIScreenEdgePanGestureRecognizer *)sender
    {
    CGFloat width = self.view.frame.size.width,
    percent = MAX(-[sender translationInView:self.view].x, 0) / width;

    switch (sender.state) {
    case UIGestureRecognizerStateBegan:
    self.navigationController.delegate = self;
    [self performSegueWithIdentifier:@"next" sender:sender];
    break;
    case UIGestureRecognizerStateChanged:
    [self.percentDrivenInteractiveTransition updateInteractiveTransition:percent];
    break;
    case UIGestureRecognizerStateEnded:
    if (percent > 0.5 || fabs([sender velocityInView:self.view].x) > 1000)
    [self.percentDrivenInteractiveTransition finishInteractiveTransition];
    else
    [self.percentDrivenInteractiveTransition cancelInteractiveTransition];
    break;
    default:
    NSLog(@"unhandled state for gesture=%@", sender);
    }
    }

    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
    {
    return [SlideAnimatedTransitioning new];
    }

    - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
    {
    self.navigationController.delegate = nil;

    if (self.edgePanGestureRecognizer.state == UIGestureRecognizerStateBegan) {
    self.percentDrivenInteractiveTransition = [UIPercentDrivenInteractiveTransition new];
    self.percentDrivenInteractiveTransition.completionCurve = UIViewAnimationOptionCurveEaseOut;
    } else {
    self.percentDrivenInteractiveTransition = nil;
    }

    return self.percentDrivenInteractiveTransition;
    }

    @end