Instantly share code, notes, and snippets.
Last active
December 16, 2015 14:27
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save mohammad19991/b3616d3aa4aa632fde00 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// MKNavigationController.m | |
// | |
// | |
// Created by Mohammad Alatrash on 7/29/15. | |
// Copyright (c) 2015 MKALatrash. All rights reserved. | |
// | |
/// A UINavigationController subclass allowing the interactive pop gesture to be recognized when the navigation bar is hidden or a custom back button is used. | |
#import "MKNavigationController.h" | |
@interface MKNavigationController ()<UINavigationControllerDelegate, UIGestureRecognizerDelegate> | |
/** | |
* A Boolean value indicating whether navigation controller is currently pushing a new view controller on the stack. | |
*/ | |
@property (nonatomic, getter = isDuringPushAnimation) BOOL duringPushAnimation; | |
/** | |
* A real delegate of the class. `delegate` property is used only for keeping an internal state during | |
* animations – we need to know when the animation ended, and that info is available only | |
* from `navigationController:didShowViewController:animated:`. | |
*/ | |
@property (weak, nonatomic) id<UINavigationControllerDelegate> realDelegate; | |
@end | |
@implementation MKNavigationController | |
#pragma mark - NSObject | |
- (void)dealloc | |
{ | |
self.delegate = nil; | |
self.interactivePopGestureRecognizer.delegate = nil; | |
} | |
#pragma mark - UIViewController | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
if (!self.delegate) { | |
self.delegate = self; | |
} | |
self.interactivePopGestureRecognizer.delegate = self; | |
} | |
#pragma mark - UINavigationController | |
- (void)setDelegate:(id<UINavigationControllerDelegate>)delegate | |
{ | |
[super setDelegate:delegate ? self : nil]; | |
self.realDelegate = delegate != self ? delegate : nil; | |
} | |
- (void)pushViewController:(UIViewController *)viewController | |
animated:(BOOL)animated __attribute__((objc_requires_super)) | |
{ | |
self.duringPushAnimation = YES; | |
[super pushViewController:viewController animated:animated]; | |
} | |
#pragma mark UINavigationControllerDelegate | |
- (void)navigationController:(UINavigationController *)navigationController | |
didShowViewController:(UIViewController *)viewController | |
animated:(BOOL)animated | |
{ | |
NSCAssert(self.interactivePopGestureRecognizer.delegate == self, @"MKNavigationController won't work correctly if you change interactivePopGestureRecognizer's delegate."); | |
self.duringPushAnimation = NO; | |
if ([self.realDelegate respondsToSelector:_cmd]) { | |
[self.realDelegate navigationController:navigationController didShowViewController:viewController animated:animated]; | |
} | |
} | |
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromVC toViewController:(UIViewController*)toVC | |
{ | |
if ([self.realDelegate respondsToSelector:_cmd]) { | |
return [self.realDelegate navigationController:navigationController animationControllerForOperation:operation fromViewController:fromVC toViewController:toVC]; | |
} | |
return nil; | |
} | |
- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController*)navigationController interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController | |
{ | |
if ([self.realDelegate respondsToSelector:_cmd]) { | |
return [self.realDelegate navigationController:navigationController interactionControllerForAnimationController:animationController]; | |
} | |
return nil; | |
} | |
#pragma mark - UIGestureRecognizerDelegate | |
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer | |
{ | |
if (gestureRecognizer == self.interactivePopGestureRecognizer) { | |
// Disable pop gesture in two situations: | |
// 1) when the pop animation is in progress | |
// 2) when user swipes quickly a couple of times and animations don't have time to be performed | |
return [self.viewControllers count] > 1 && !self.isDuringPushAnimation; | |
} else { | |
// default value | |
return YES; | |
} | |
} | |
#pragma mark - Delegate Forwarder | |
// Thanks for the idea goes to: https://github.com/steipete/PSPDFTextView/blob/ee9ce04ad04217efe0bc84d67f3895a34252d37c/PSPDFTextView/PSPDFTextView.m#L148-164 | |
- (BOOL)respondsToSelector:(SEL)s | |
{ | |
return [super respondsToSelector:s] || [self.realDelegate respondsToSelector:s]; | |
} | |
- (NSMethodSignature *)methodSignatureForSelector:(SEL)s | |
{ | |
return [super methodSignatureForSelector:s] ?: [(id)self.realDelegate methodSignatureForSelector:s]; | |
} | |
- (void)forwardInvocation:(NSInvocation *)invocation | |
{ | |
id delegate = self.realDelegate; | |
if ([delegate respondsToSelector:invocation.selector]) { | |
[invocation invokeWithTarget:delegate]; | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment