Skip to content

Instantly share code, notes, and snippets.

@cyborch
Created October 18, 2011 19:59
Show Gist options
  • Save cyborch/1296526 to your computer and use it in GitHub Desktop.
Save cyborch/1296526 to your computer and use it in GitHub Desktop.
//
// 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
//
// 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