Instantly share code, notes, and snippets.
Created
October 18, 2011 19:59
-
Star
1
(1)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save cyborch/1296526 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
// | |
// BPNavigationController.h | |
// StatusBarSize | |
// | |
// Created by Anders Borch on 10/16/11. | |
// Copyright (c) 2011 Bump. All rights reserved. | |
// | |
#import <UIKit/UIKit.h> | |
@interface BPNavigationController : UINavigationController | |
/*! | |
@method setup | |
@abstract Setup UINavigationController to handle non-fullscreen modals. | |
@discussion | |
This will replace the implementation of presentModalViewController:animated: with a new implementation | |
which retains the original frame of the UINavigationController#view and pushes a | |
*/ | |
+ (void)setup; | |
@end |
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
// | |
// BPNavigationController.m | |
// StatusBarSize | |
// | |
// Created by Anders Borch on 10/16/11. | |
// Copyright (c) 2011 Bump. All rights reserved. | |
// | |
#import "BPNavigationController.h" | |
#import <objc/runtime.h> | |
@interface UINavigationController (BPNavigationController) | |
- (void)_bp_presentModalViewController:(UIViewController*)controller animated:(BOOL)animated; | |
- (void)_bp_dismissModalViewControllerAnimated:(BOOL)animated; | |
@end | |
#pragma mark - Helper | |
@interface BPNavigationControllerInvocationHelper : NSObject { | |
UIViewController *_controller; | |
CGRect _frame; | |
id<UINavigationControllerDelegate> _delegate; | |
} | |
@property (nonatomic,retain) UIViewController *controller; | |
@property (nonatomic,assign) CGRect frame; | |
@property (nonatomic,retain) id<UINavigationControllerDelegate> delegate; | |
@end | |
@implementation BPNavigationControllerInvocationHelper | |
@synthesize controller=_controller, frame=_frame, delegate=_delegate; | |
- (void)dealloc | |
{ | |
self.controller = nil; | |
self.delegate = nil; | |
[super dealloc]; | |
} | |
@end | |
#pragma mark - Replacement definitions | |
void present_helper(UINavigationController *self, SEL _cmd, BPNavigationControllerInvocationHelper *helper); | |
void present(UINavigationController *self, SEL _cmd, UIViewController *controller, BOOL animated); | |
void dismiss(UINavigationController *self, SEL _cmd, BOOL animated); | |
#pragma mark - Replacement implementations | |
void present_helper(UINavigationController *self, SEL _cmd, BPNavigationControllerInvocationHelper *helper) | |
{ | |
// reset the frame | |
self.view.frame = helper.frame; | |
helper.controller.view.frame = helper.frame; | |
// notify delegate of completion | |
[helper.delegate navigationController: self | |
didShowViewController: helper.controller | |
animated: YES]; | |
self.delegate = helper.delegate; | |
} | |
void present(UINavigationController *self, SEL _cmd, UIViewController *controller, BOOL animated) | |
{ | |
CGRect rect = [self.view frame]; | |
controller.view.frame = CGRectOffset(rect, 0.0f, rect.size.height); | |
[self.view addSubview: controller.view]; | |
BPNavigationControllerInvocationHelper *helper = [[BPNavigationControllerInvocationHelper alloc] init]; | |
helper.controller = controller; | |
helper.frame = rect; | |
if (animated) { | |
// manual notification of delegate | |
helper.delegate = self.delegate; | |
self.delegate = nil; | |
[helper.delegate navigationController: self | |
willShowViewController: controller | |
animated: YES]; | |
[UIView animateWithDuration: 0.3 | |
delay: 0.0 | |
options: UIViewAnimationCurveEaseOut | |
animations: ^{ | |
helper.controller.view.frame = self.view.bounds; | |
} | |
completion: ^(BOOL finished) { | |
// call the *original* method | |
[self _bp_presentModalViewController: controller | |
animated: NO]; | |
if (finished) { | |
// reset the frame and notify delegate | |
[self performSelector: @selector(_bp_presentModalViewControllerWithHelper:) | |
withObject: helper | |
afterDelay: 0.0]; | |
} | |
[helper release]; | |
}]; | |
} else { | |
// call the *original* method | |
[self _bp_presentModalViewController: controller | |
animated: NO]; | |
// reset the frame | |
[self performSelector: @selector(_bp_presentModalViewControllerWithHelper:) | |
withObject: helper | |
afterDelay: 0.0]; | |
[helper release]; | |
} | |
} | |
void dismiss(UINavigationController *self, SEL _cmd, BOOL animated) | |
{ | |
CGRect rect = [self.view frame]; | |
UIViewController *controller = [self.modalViewController retain]; | |
id<UINavigationControllerDelegate> _delegate = self.delegate; | |
if (animated) { | |
// manual notification of delegate | |
self.delegate = nil; | |
[_delegate navigationController: self | |
willShowViewController: self.topViewController | |
animated: YES]; | |
} | |
// call the *original* method | |
[self _bp_dismissModalViewControllerAnimated: NO]; | |
// reset the navigation frame | |
self.view.frame = rect; | |
if (animated) { | |
[self.view addSubview: controller.view]; | |
controller.view.frame = self.view.bounds; | |
[UIView animateWithDuration: 0.3 | |
delay: 0.0 | |
options: UIViewAnimationCurveEaseIn | |
animations: ^{ | |
controller.view.frame = CGRectOffset(rect, 0.0f, rect.size.height); | |
} | |
completion: ^(BOOL finished) { | |
[controller.view removeFromSuperview]; | |
[controller release]; | |
// manual notification of delegate | |
[_delegate navigationController: self | |
didShowViewController: self.topViewController | |
animated: YES]; | |
self.delegate = _delegate; | |
}]; | |
} else { | |
[controller release]; | |
} | |
} | |
#pragma mark - | |
@implementation BPNavigationController | |
+ (void)setup { | |
class_addMethod([UINavigationController class], | |
@selector(_bp_presentModalViewController:animated:), | |
(IMP)present, | |
"v@:@c"); | |
class_addMethod([UINavigationController class], | |
@selector(_bp_presentModalViewControllerWithHelper:), | |
(IMP)present_helper, | |
"v@:@"); | |
class_addMethod([UINavigationController class], | |
@selector(_bp_dismissModalViewControllerAnimated:), | |
(IMP)dismiss, | |
"v@:c"); | |
// replace present modal | |
Method orig_method = nil, alt_method = nil; | |
orig_method = class_getInstanceMethod([UINavigationController class], | |
@selector(presentModalViewController:animated:)); | |
alt_method = class_getInstanceMethod([UINavigationController class], | |
@selector(_bp_presentModalViewController:animated:)); | |
method_exchangeImplementations(orig_method, alt_method); | |
// replace dismiss modal | |
orig_method = class_getInstanceMethod([UINavigationController class], | |
@selector(dismissModalViewControllerAnimated:)); | |
alt_method = class_getInstanceMethod([UINavigationController class], | |
@selector(_bp_dismissModalViewControllerAnimated:)); | |
method_exchangeImplementations(orig_method, alt_method); | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment