Skip to content

Instantly share code, notes, and snippets.

@ArtFeel
Last active August 1, 2019 21:23
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ArtFeel/7690431 to your computer and use it in GitHub Desktop.
Save ArtFeel/7690431 to your computer and use it in GitHub Desktop.
Simple sliding transitioning for navigation controller mimics pre iOS7 push/pop animations.All you need, is simply set delegate for you navigation controller: self.navigationController.delegate = self.navigationTransitioningDelegate;NavigationController does not retain delegate, so you should hold it. Note: this code is free (http://unlicense.org)
//
// MGNavigationTransitioningDelegate
//
// Created by Philip Vasilchenko on 27.11.13.
//
#import <UIKit/UIKit.h>
@interface MGNavigationTransitioningDelegate : NSObject <UINavigationControllerDelegate>
@property (nonatomic, strong) id<UIViewControllerAnimatedTransitioning> pushTransitioning;
@property (nonatomic, strong) id<UIViewControllerAnimatedTransitioning> popTransitioning;
@end
//
// MGNavigationTransitioningDelegate
//
// Created by Philip Vasilchenko on 27.11.13.
//
#import "MGNavigationTransitioningDelegate.h"
#import "MGSlideAnimatedTransitioning.h"
@implementation MGNavigationTransitioningDelegate
- (id)init {
self = [super init];
if ( self ) {
self.pushTransitioning = [MGSlideAnimatedTransitioning transitioningWithReverse:NO];
self.popTransitioning = [MGSlideAnimatedTransitioning transitioningWithReverse:YES];
}
return self;
}
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromViewController
toViewController:(UIViewController*)toViewController {
return operation == UINavigationControllerOperationPush ? self.pushTransitioning : self.popTransitioning;
}
@end
//
// MGSlideAnimatedTransitioning
//
// Created by Philip Vasilchenko on 27.11.13.
//
#import <UIKit/UIKit.h>
@interface MGSlideAnimatedTransitioning : NSObject <UIViewControllerAnimatedTransitioning>
@property (nonatomic, assign) BOOL reverse;
- (instancetype)initWithReverse:(BOOL)reverse;
+ (instancetype)transitioningWithReverse:(BOOL)reverse;
@end
//
// MGSlideAnimatedTransitioning
//
// Created by Philip Vasilchenko on 27.11.13.
//
#import "MGSlideAnimatedTransitioning.h"
@implementation MGSlideAnimatedTransitioning
static const NSTimeInterval kMGSlideAnimatedTransitioningDuration = 0.3f;
#pragma mark - Initialization
- (instancetype)initWithReverse:(BOOL)reverse {
self = [super init];
if ( self ) {
self.reverse = reverse;
}
return self;
}
+ (instancetype)transitioningWithReverse:(BOOL)reverse {
return [[self alloc] initWithReverse:reverse];
}
#pragma mark - Transitioning
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
NSString * fromKey = UITransitionContextFromViewControllerKey;
NSString * toKey = UITransitionContextToViewControllerKey;
UIViewController * fromViewController = [transitionContext viewControllerForKey:fromKey];
UIViewController * toViewController = [transitionContext viewControllerForKey:toKey];
UIView * containerView = [transitionContext containerView];
UIView * fromView = fromViewController.view;
UIView * toView = toViewController.view;
NSTimeInterval duration = [self transitionDuration:transitionContext];
CGFloat viewWidth = CGRectGetWidth(containerView.frame);
__block CGRect fromViewFrame = fromView.frame;
__block CGRect toViewFrame = toView.frame;
toViewFrame.origin.x = self.reverse ? -viewWidth : viewWidth;
toView.frame = toViewFrame;
[containerView addSubview:toView];
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
toViewFrame.origin.x = CGRectGetMinX(containerView.frame);
fromViewFrame.origin.x = self.reverse ? viewWidth : -viewWidth;
toView.frame = toViewFrame;
fromView.frame = fromViewFrame;
}
completion:^(BOOL finished) {
if ( self.reverse ) { [fromView removeFromSuperview]; }
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return kMGSlideAnimatedTransitioningDuration;
}
@end
@StanchoBancho
Copy link

You have 4 small errors:

  1. fromVC should be fromViewController (you didn`t rename it on the row 40)
  2. The same as 1 but for toVC
  3. In order to change fromViewFrame inside a block you should declare it like that __block CGRect fromViewFrame = fromView.frame;
  4. The same as 3 but for toViewFrame

But if we skip that, your solution is cool. :)

@annca
Copy link

annca commented Dec 14, 2013

I second @StanchoBancho, those edits need to be made. Works after that. Thanks!

@ArtFeel
Copy link
Author

ArtFeel commented Dec 25, 2013

@StanchoBancho, thanks for the feedback, I fixed it.
In my previous code I'm using FrameAccessor pod, highly recommend it.

@ubisys
Copy link

ubisys commented Apr 14, 2014

Great approach!

In case the navigation bar is hidden for one view controller and visible for the other, you need a little adjustment. In the animation block, below line 56, add:

        toViewFrame.origin.y = toViewController.navigationController.navigationBarHidden ?
            0 : toViewController.navigationController.navigationBar.frame.origin.y +
            toViewController.navigationController.navigationBar.frame.size.height;

@tommybananas
Copy link

Works great with swift too - thanks

@vishundayal
Copy link

Navigation bar does not move along with viewcontroller, results in navigationbar updates later. Can anyone please give a fix for this?

@alexiscreuzot
Copy link

Any idea on how to get this to be interactive?

@tapannathvani
Copy link

Can you please tell me how to use these classes in my project ?

@jaramire
Copy link

jaramire commented Nov 2, 2016

Hello,
Although this brought back the transition I needed, if I rotated my app after using the transition and then transitioned back, the frame would be the "old" frame and not the new rotation. I had to make this change to make sure I was transitioning back to the proper view:
//__block CGRect toViewFrame = toView.frame;
__block CGRect toViewFrame = [transitionContext finalFrameForViewController:toViewController];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment