redmine-mobile-syncgithub/RedmineMobile/Libs/PPRevealSideViewController/PPRevealSideViewController.m

1442 lines
59 KiB
Objective-C
Executable File

//
// PPRevealSideViewController.m
// PPRevealSideViewController
//
// Created by Marian PAUL on 16/02/12.
// Copyright (c) 2012 Marian PAUL aka ipodishima — iPuP SARL. All rights reserved.
//
#import "PPRevealSideViewController.h"
#import <QuartzCore/QuartzCore.h>
#import <objc/runtime.h>
@interface PPRevealSideViewController (Private)
- (void) setRootViewController:(UIViewController *)controller replaceToOrigin:(BOOL)replace;
- (void) setRootViewController:(UIViewController*)controller;
- (void) addShadow;
- (void) removeShadow;
- (void) handleShadows;
- (void) informDelegateWithOptionalSelector:(SEL)selector withParam:(id)param;
- (void) popViewControllerWithNewCenterController:(UIViewController *)centerController animated:(BOOL)animated andPresentNewController:(UIViewController*)controllerToPush withDirection:(PPRevealSideDirection)direction andOffset:(CGFloat)offset;
- (void) addGesturesToCenterController;
- (void) addPanGestureToController:(UIViewController*)controller;
- (void) addTapGestureToController:(UIViewController*)controller;
- (void) addGesturesToController:(UIViewController*)controller;
- (void) removeAllPanGestures;
- (void) removeAllTapGestures;
- (void) removeAllGestures;
- (void) setOffset:(CGFloat)offset forDirection:(PPRevealSideDirection)direction;
- (void) removeControllerFromView:(UIViewController*)controller animated:(BOOL)animated;
- (BOOL) isLeftControllerClosed;
- (BOOL) isRightControllerClosed;
- (BOOL) isTopControllerClosed;
- (BOOL) isBottomControllerClosed;
- (BOOL) isOptionEnabled:(PPRevealSideOptions)option;
- (BOOL) canCrossOffsets;
- (PPRevealSideDirection) getSideToClose;
- (CGRect) getSlidingRectForOffset:(CGFloat)offset forDirection:(PPRevealSideDirection)direction;
- (CGRect) getSideViewFrameFromRootFrame:(CGRect)rootFrame andDirection:(PPRevealSideDirection)direction;
- (UIEdgeInsets) getEdgetInsetForDirection:(PPRevealSideDirection)direction;
- (CGFloat) getOffsetForDirection:(PPRevealSideDirection)direction andInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
- (CGFloat) getOffsetForDirection:(PPRevealSideDirection)direction;
@end
@implementation PPRevealSideViewController
@synthesize rootViewController = _rootViewController;
@synthesize panInteractionsWhenClosed = _panInteractionsWhenClosed;
@synthesize panInteractionsWhenOpened = _panInteractionsWhenOpened;
@synthesize tapInteractionsWhenOpened = _tapInteractionsWhenOpened;
@synthesize directionsToShowBounce = _directionsToShowBounce;
@synthesize options = _options;
@synthesize bouncingOffset = _bouncingOffset;
@synthesize delegate = _delegate;
- (id) initWithRootViewController:(UIViewController*)rootViewController {
self = [super init];
if (self) {
// set default options
self.options = PPRevealSideOptionsShowShadows | PPRevealSideOptionsBounceAnimations | PPRevealSideOptionsCloseCompletlyBeforeOpeningNewDirection;
self.bouncingOffset = -1.0;
self.panInteractionsWhenClosed = PPRevealSideInteractionNavigationBar;
self.panInteractionsWhenOpened = PPRevealSideInteractionNavigationBar | PPRevealSideInteractionContentView;
self.tapInteractionsWhenOpened = PPRevealSideInteractionContentView | PPRevealSideInteractionNavigationBar;
self.directionsToShowBounce = PPRevealSideDirectionBottom | PPRevealSideDirectionLeft | PPRevealSideDirectionRight | PPRevealSideDirectionTop;
_viewControllers = [[NSMutableDictionary alloc] init];
_viewControllersOffsets = [[NSMutableDictionary alloc] init];
_gestures = [[NSMutableArray alloc] init];
[self setRootViewController:rootViewController];
}
return self;
}
#pragma mark - View lifecycle
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
CGRect rect = PPScreenBounds();
rect.size.height -= PPStatusBarHeight();
self.view = PP_AUTORELEASE([[UIView alloc] initWithFrame:rect]);
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.view.clipsToBounds = YES;
self.view.autoresizesSubviews = YES;
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[_rootViewController viewWillAppear:animated];
PPRevealSideDirection direction = [self getSideToClose];
if (direction != PPRevealSideDirectionNone) [[_viewControllers objectForKey:[NSNumber numberWithInt:direction]] viewWillAppear:animated];
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[_rootViewController viewDidAppear:animated];
PPRevealSideDirection direction = [self getSideToClose];
if (direction != PPRevealSideDirectionNone) [[_viewControllers objectForKey:[NSNumber numberWithInt:direction]] viewDidAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[_rootViewController viewWillDisappear:animated];
PPRevealSideDirection direction = [self getSideToClose];
if (direction != PPRevealSideDirectionNone) [[_viewControllers objectForKey:[NSNumber numberWithInt:direction]] viewWillDisappear:animated];
}
- (void) viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[_rootViewController viewDidDisappear:animated];
PPRevealSideDirection direction = [self getSideToClose];
if (direction != PPRevealSideDirectionNone) [[_viewControllers objectForKey:[NSNumber numberWithInt:direction]] viewDidDisappear:animated];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
if (_rootViewController && !_rootViewController.view.superview)
{
// Then we have probably received memory warning
UIViewController *newRoot = PP_RETAIN(_rootViewController);
// Just a little hack to reset the root
self.rootViewController = nil;
self.rootViewController = newRoot;
PP_RELEASE(newRoot);
}
}
#pragma mark - Push and pop methods
#define DefaultOffset 70.0
#define DefaultOffsetBouncing 5.0
#define OpenAnimationTime 0.3
#define OpenAnimationTimeBouncingRatio 0.3
- (void) pushViewController:(UIViewController*)controller onDirection:(PPRevealSideDirection)direction animated:(BOOL)animated {
[self pushViewController:controller
onDirection:direction
withOffset:DefaultOffset
animated:animated];
}
- (void) pushViewController:(UIViewController*)controller onDirection:(PPRevealSideDirection)direction animated:(BOOL)animated forceToPopPush:(BOOL)forcePopPush {
[self pushViewController:controller
onDirection:direction
withOffset:DefaultOffset
animated:animated
forceToPopPush:forcePopPush];
}
- (void) pushOldViewControllerOnDirection:(PPRevealSideDirection)direction animated:(BOOL)animated {
[self pushOldViewControllerOnDirection:direction
withOffset:DefaultOffset
animated:animated];
}
#define BOUNCE_ERROR_OFFSET 14.0
- (void) pushOldViewControllerOnDirection:(PPRevealSideDirection)direction withOffset:(CGFloat)offset animated:(BOOL)animated {
UIViewController *oldController = [_viewControllers objectForKey:[NSNumber numberWithInt:direction]];
if (oldController) {
[self pushViewController:oldController
onDirection:direction
withOffset:offset
animated:animated];
}
else
{
if ((_directionsToShowBounce & direction) == direction) {
// make a small animation to indicate that there is not yet a controller
CGRect originalFrame = _rootViewController.view.frame;
_animationInProgress = YES;
[UIView animateWithDuration:OpenAnimationTime*0.15
delay:0.0
options:UIViewAnimationCurveEaseInOut
animations:^{
CGFloat offsetBounce;
if (direction == PPRevealSideDirectionLeft || direction == PPRevealSideDirectionRight)
offsetBounce = CGRectGetWidth(_rootViewController.view.frame)-BOUNCE_ERROR_OFFSET;
else
offsetBounce = CGRectGetHeight(_rootViewController.view.frame)-BOUNCE_ERROR_OFFSET;
_rootViewController.view.frame = [self getSlidingRectForOffset:offsetBounce
forDirection:direction];
} completion:^(BOOL finished) {
[UIView animateWithDuration:OpenAnimationTime*0.15
delay:0.0
options:UIViewAnimationCurveEaseInOut
animations:^{
_rootViewController.view.frame = originalFrame;
} completion:^(BOOL finished) {
_animationInProgress = NO;
}];
}];
}
}
}
- (void) pushViewController:(UIViewController*)controller onDirection:(PPRevealSideDirection)direction withOffset:(CGFloat)offset animated:(BOOL)animated {
[self pushViewController:controller
onDirection:direction
withOffset:offset
animated:animated
forceToPopPush:NO];
}
- (void) pushViewController:(UIViewController *)controller onDirection:(PPRevealSideDirection)direction withOffset:(CGFloat)offset animated:(BOOL)animated forceToPopPush:(BOOL)forcePopPush {
[self informDelegateWithOptionalSelector:@selector(pprevealSideViewController:willPushController:) withParam:controller];
// get the side direction to close
PPRevealSideDirection directionToClose = [self getSideToClose];
// if this is the same direction, then close it
if (directionToClose == direction && !_shouldNotCloseWhenPushingSameDirection) {
if (!forcePopPush) {
// then pop
[self popViewControllerWithNewCenterController:_rootViewController animated:animated];
}
else
{
// pop and push
[self popViewControllerWithNewCenterController:_rootViewController
animated:animated
andPresentNewController:controller
withDirection:direction
andOffset:offset];
}
return;
}
else // if the direction is different, and we close completely before opening, then pop / push !
if (directionToClose != PPRevealSideDirectionNone && [self isOptionEnabled:PPRevealSideOptionsCloseCompletlyBeforeOpeningNewDirection] && !_shouldNotCloseWhenPushingSameDirection) {
[self popViewControllerWithNewCenterController:_rootViewController
animated:animated
andPresentNewController:controller withDirection:direction andOffset:offset];
return;
}
_animationInProgress = YES;
NSNumber *directionNumber = [NSNumber numberWithInt:direction];
// save the offset
[self setOffset:offset forDirection:direction];
// get the offset with orientation aware stuff
offset = [self getOffsetForDirection:direction];
// save the controller and remove the old one from the view
UIViewController *oldController = [_viewControllers objectForKey:directionNumber];
if (controller != oldController) [self removeControllerFromView:oldController animated:animated];
[_viewControllers setObject:controller forKey:directionNumber];
// set the container controller to self
controller.revealSideViewController = self;
// Place the controller juste below the rootviewcontroller
controller.view.frame = self.view.bounds; // handle layout issue with navigation bar. Comment to see the crap, then push a nav controller
[self removeControllerFromView:controller animated:animated];
// TODO remove then adding not so good ... Maybe do something different
if (PPSystemVersionGreaterOrEqualThan(5.0))
{
[controller willMoveToParentViewController:self];
[self addChildViewController:controller];
}
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [controller viewWillAppear:animated];
[self.view insertSubview:controller.view belowSubview:_rootViewController.view];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [controller viewDidAppear:animated];
// if bounces is activated and the push is animated, calculate the first frame with the bounce
CGRect rootFrame = CGRectZero;
if ([self canCrossOffsets] && animated) // then we make an offset
rootFrame = [self getSlidingRectForOffset:offset- ((_bouncingOffset == - 1.0) ? DefaultOffsetBouncing : _bouncingOffset) forDirection:direction];
else
rootFrame = [self getSlidingRectForOffset:offset forDirection:direction];
void (^openAnimBlock)(void) = ^(void) {
controller.view.hidden = NO;
_rootViewController.view.frame = rootFrame;
};
// replace the view since IB add some offsets with the status bar if enabled
controller.view.frame = [self getSideViewFrameFromRootFrame:rootFrame
andDirection:direction];
NSTimeInterval animationTime = OpenAnimationTime;
// if ([self canCrossOffsets]) animationTime = OpenAnimationTime;
// else animationTime = OpenAnimationTime;
UIViewAnimationOptions options = UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionLayoutSubviews;
if (animated) {
[UIView animateWithDuration:animationTime
delay:0.0
options:options
animations:openAnimBlock
completion:^(BOOL finished) {
if ([self canCrossOffsets]) // then we come to normal
{
[UIView animateWithDuration:OpenAnimationTime*OpenAnimationTimeBouncingRatio
delay:0.0
options:options
animations:^{
_rootViewController.view.frame = [self getSlidingRectForOffset:offset forDirection:direction];
} completion:^(BOOL finished) {
_animationInProgress = NO;
if (PPSystemVersionGreaterOrEqualThan(5.0)) [controller didMoveToParentViewController:self];
[self informDelegateWithOptionalSelector:@selector(pprevealSideViewController:didPushController:) withParam:controller];
}];
}
else
{
_animationInProgress = NO;
if (PPSystemVersionGreaterOrEqualThan(5.0)) [controller didMoveToParentViewController:self];
[self informDelegateWithOptionalSelector:@selector(pprevealSideViewController:didPushController:) withParam:controller];
}
}];
}
else {
openAnimBlock();
_animationInProgress = NO;
if (PPSystemVersionGreaterOrEqualThan(5.0)) [controller didMoveToParentViewController:self];
[self informDelegateWithOptionalSelector:@selector(pprevealSideViewController:didPushController:) withParam:controller];
}
}
- (void) popViewControllerWithNewCenterController:(UIViewController*)centerController animated:(BOOL)animated {
[self popViewControllerWithNewCenterController:centerController
animated:animated
andPresentNewController:nil
withDirection:PPRevealSideDirectionNone
andOffset:0.0];
}
- (void) popViewControllerAnimated:(BOOL)animated {
[self popViewControllerWithNewCenterController:_rootViewController
animated:animated];
}
- (void) popViewControllerWithNewCenterController:(UIViewController *)centerController animated:(BOOL)animated andPresentNewController:(UIViewController *)controllerToPush withDirection:(PPRevealSideDirection)direction andOffset:(CGFloat)offset {
[self informDelegateWithOptionalSelector:@selector(pprevealSideViewController:willPopToController:) withParam:centerController];
PPRevealSideDirection directionToClose = [self getSideToClose];
if (directionToClose == PPRevealSideDirectionNone && _popFromPanGesture)
{
directionToClose = _currentPanDirection;
_popFromPanGesture = NO;
}
UIViewAnimationOptions options = UIViewAnimationOptionCurveEaseOut;
_animationInProgress = YES;
// define the close anim block
void (^bigAnimBlock)(BOOL) = ^(BOOL finished) {
if (finished) {
CGRect oldFrame = _rootViewController.view.frame;
centerController.view.frame = oldFrame;
[self setRootViewController:centerController replaceToOrigin:NO];
// this is the anim block to put to normal the center controller
void(^smallAnimBlock)(void) = ^(void) {
CGRect newFrame = _rootViewController.view.frame;
newFrame.origin.x = 0.0;
newFrame.origin.y = 0.0;
_rootViewController.view.frame = newFrame;
};
// this is the completion block when you pop then push the new controller
void (^smallAnimBlockCompletion)(BOOL) = ^(BOOL finished) {
if (finished) {
[self informDelegateWithOptionalSelector:@selector(pprevealSideViewController:didPopToController:) withParam:centerController];
// remove the view (don't need to surcharge (not english this word ? ... ) all the interface).
UIViewController *oldController = (UIViewController*)[_viewControllers objectForKey:[NSNumber numberWithInt:directionToClose]];
[self removeControllerFromView:oldController animated:animated];
_animationInProgress = NO;
if (controllerToPush) {
[self pushViewController:controllerToPush
onDirection:direction
withOffset:offset
animated:animated];
}
}
};
// execute the blocks depending on animated or not
if (animated) {
NSTimeInterval animationTime = OpenAnimationTime;
// if ([self canCrossOffsets]) animationTime = OpenAnimationTime;
// else animationTime = OpenAnimationTime;
[UIView animateWithDuration:animationTime
delay:0.0
options:options
animations:smallAnimBlock
completion:smallAnimBlockCompletion];
}
else
{
smallAnimBlock();
smallAnimBlockCompletion(YES);
}
}
};
// Now we are gonna use the big block !!
if ([self canCrossOffsets] && animated && centerController != _rootViewController) {
PPRevealSideDirection directionToOpen = [self getSideToClose];
// open completely and then close it
[UIView animateWithDuration:OpenAnimationTime*OpenAnimationTimeBouncingRatio
delay:0.0
options:options
animations:^{
// this will open completely the view
_rootViewController.view.frame = [self getSlidingRectForOffset:0.0 forDirection:directionToOpen];
} completion:bigAnimBlock];
}
else
{
// we just execute the close anim block
// Badly, we can't use the bigAnimBlock as an animation block since there is the finished parameter. So, just execute it !
if (animated) {
[UIView animateWithDuration:OpenAnimationTime
delay:0.0
options:options
animations:^{
bigAnimBlock(YES);
} completion:^(BOOL finished) {
} ];
}
else
bigAnimBlock(YES);
}
}
- (void) preloadViewController:(UIViewController*)controller forSide:(PPRevealSideDirection)direction {
[self preloadViewController:controller
forSide:direction
withOffset:DefaultOffset];
}
- (void) preloadViewController:(UIViewController*)controller forSide:(PPRevealSideDirection)direction withOffset:(CGFloat)offset {
UIViewController *existingController = [_viewControllers objectForKey:[NSNumber numberWithInt:direction]];
if (existingController != controller) {
if (existingController.view.superview) [self removeControllerFromView:existingController animated:NO];
[_viewControllers setObject:controller forKey:[NSNumber numberWithInt:direction]];
if (![controller isViewLoaded]) {
if (PPSystemVersionGreaterOrEqualThan(5.0)) [controller willMoveToParentViewController:self];
[self.view insertSubview:controller.view atIndex:0];
if (PPSystemVersionGreaterOrEqualThan(5.0))
{
[self addChildViewController:controller];
[controller didMoveToParentViewController:self];
}
controller.view.hidden = YES;
}
controller.view.frame = self.view.bounds;
}
[self setOffset:offset forDirection:direction];
}
- (void) unloadViewControllerForSide:(PPRevealSideDirection)direction
{
NSNumber *key = [NSNumber numberWithInt:direction];
UIViewController *controller = [_viewControllers objectForKey:key];
[self removeControllerFromView:controller animated:NO];
[_viewControllers removeObjectForKey:key];
}
- (void) changeOffset:(CGFloat)offset forDirection:(PPRevealSideDirection)direction {
[self changeOffset:offset forDirection:direction animated:NO];
}
- (void) changeOffset:(CGFloat)offset forDirection:(PPRevealSideDirection)direction animated:(BOOL)animated {
[self setOffset:offset forDirection:direction];
if ([self getSideToClose] == direction ) {
if (animated)
[UIView animateWithDuration:0.3
animations:^{
_rootViewController.view.frame = [self getSlidingRectForOffset:offset
forDirection:direction];
}];
else
_rootViewController.view.frame = [self getSlidingRectForOffset:offset
forDirection:direction];
}
}
#pragma mark - Observation method
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"view.frame"]) {
PPRevealSideDirection direction = [self getSideToClose];
UIViewController *openedController = [_viewControllers objectForKey:[NSNumber numberWithInt:direction]];
if (openedController) {
openedController.view.revealSideInset = [self getEdgetInsetForDirection:direction];
}
}
else
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
#pragma mark - Setters
- (void) setOptions:(PPRevealSideOptions)options {
[self willChangeValueForKey:@"options"];
_options = options;
[self handleShadows];
[self didChangeValueForKey:@"options"];
}
- (void) setOption:(PPRevealSideOptions)option {
_options |= option;
if (option == PPRevealSideOptionsShowShadows) [self handleShadows];
}
- (void) resetOption:(PPRevealSideOptions)option {
_options ^= option;
if (option == PPRevealSideOptionsShowShadows) [self handleShadows];
}
- (void) setPanInteractionsWhenClosed:(PPRevealSideInteractions)panInteractionsWhenClosed {
[self willChangeValueForKey:@"panInteractionsWhenClosed"];
_panInteractionsWhenClosed = panInteractionsWhenClosed;
[self addGesturesToCenterController];
[self didChangeValueForKey:@"panInteractionsWhenClosed"];
}
- (void) setPanInteractionsWhenOpened:(PPRevealSideInteractions)panInteractionsWhenOpened {
[self willChangeValueForKey:@"panInteractionsWhenOpened"];
_panInteractionsWhenOpened = panInteractionsWhenOpened;
[self addGesturesToCenterController];
[self didChangeValueForKey:@"panInteractionsWhenOpened"];
}
- (void) setTapInteractionsWhenOpened:(PPRevealSideInteractions)tapInteractionsWhenOpened {
[self willChangeValueForKey:@"tapInteractionsWhenOpened"];
_tapInteractionsWhenOpened = tapInteractionsWhenOpened;
[self addGesturesToCenterController];
[self didChangeValueForKey:@"tapInteractionsWhenOpened"];
}
#pragma mark - Getters
- (PPRevealSideDirection) sideDirectionOpened
{
return [self getSideToClose];
}
#pragma mark - Private methods
- (void) setRootViewController:(UIViewController *)controller replaceToOrigin:(BOOL)replace
{
if (_rootViewController != controller) {
[self willChangeValueForKey:@"rootViewController"];
[self removeAllGestures];
@try {
[_rootViewController removeObserver:self forKeyPath:@"view.frame"];
}
@catch (NSException *exception) {
}
@finally {
}
[self removeControllerFromView:_rootViewController animated:NO];
_rootViewController = PP_RETAIN(controller);
_rootViewController.revealSideViewController = self;
if (PPSystemVersionGreaterOrEqualThan(5.0))
{
[_rootViewController willMoveToParentViewController:self];
[self addChildViewController:_rootViewController];
}
[self handleShadows];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [_rootViewController viewWillAppear:NO];
[self.view addSubview:_rootViewController.view];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [_rootViewController viewDidAppear:NO];
if (PPSystemVersionGreaterOrEqualThan(5.0))
[_rootViewController didMoveToParentViewController:self];
[_rootViewController addObserver:self
forKeyPath:@"view.frame"
options:NSKeyValueObservingOptionNew
context:NULL];
[self addGesturesToCenterController];
if (replace)
_rootViewController.view.frame = self.view.bounds;
[self didChangeValueForKey:@"rootViewController"];
}
}
- (void) setRootViewController:(UIViewController *)controller
{
[self setRootViewController:controller replaceToOrigin:YES];
}
- (void) addShadow
{
_rootViewController.view.layer.shadowOffset = CGSizeZero;
_rootViewController.view.layer.shadowOpacity = 0.75f;
_rootViewController.view.layer.shadowRadius = 10.0f;
_rootViewController.view.layer.shadowColor = [UIColor blackColor].CGColor;
_rootViewController.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.layer.bounds].CGPath;
_rootViewController.view.clipsToBounds = NO;
}
- (void) removeShadow
{
_rootViewController.view.layer.shadowPath = nil;
_rootViewController.view.layer.shadowOpacity = 0.0f;
_rootViewController.view.layer.shadowRadius = 0.0;
_rootViewController.view.layer.shadowColor = nil;
}
- (void) handleShadows {
if ([self isOptionEnabled:PPRevealSideOptionsShowShadows]) {
[self addShadow];
}
else
{
[self removeShadow];
}
}
- (void) informDelegateWithOptionalSelector:(SEL)selector withParam:(id)param {
if ([self.delegate respondsToSelector:selector]) {
// suppression of 'performSelector may cause a leak because its selector is unknown' warning
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self.delegate performSelector:selector withObject:self withObject:param];
#pragma clang diagnostic pop
}
if (selector == @selector(pprevealSideViewController:didPushController:)
||
selector == @selector(pprevealSideViewController:didPopToController:)) {
[self addGesturesToCenterController];
}
}
- (void) resizeCurrentView {
PPRevealSideDirection direction = [self getSideToClose];
if (
([self isOptionEnabled:PPRevealSideOptionsKeepOffsetOnRotation] && (direction == PPRevealSideDirectionRight || direction == PPRevealSideDirectionLeft))
||
(direction == PPRevealSideDirectionBottom || direction == PPRevealSideDirectionTop)
) {
_rootViewController.view.frame = [self getSlidingRectForOffset:[self getOffsetForDirection:direction]
forDirection:direction];
}
}
- (UIViewController*) getControllerForGestures
{
UIViewController *controllerForGestures = _rootViewController;
if ([self.delegate respondsToSelector:@selector(controllerForGesturesOnPPRevealSideViewController:)]) {
UIViewController *specialController = [self.delegate controllerForGesturesOnPPRevealSideViewController:self];
if (specialController) controllerForGestures = specialController;
}
return controllerForGestures;
}
- (void) addPanGestureToController:(UIViewController*)controller {
BOOL isClosed = ([self getSideToClose] == PPRevealSideDirectionNone) ? YES : NO;
PPRevealSideInteractions interactions = isClosed ? _panInteractionsWhenClosed : _panInteractionsWhenOpened;
if (interactions & PPRevealSideInteractionNavigationBar && ([controller isKindOfClass:[UINavigationController class]] || controller.navigationController)) {
UIPanGestureRecognizer* panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureRecognizerDidPan:)];
panGesture.cancelsTouchesInView = YES;
panGesture.delegate = self;
UINavigationController *nav;
if ([controller isKindOfClass:[UINavigationController class]])
nav = (UINavigationController*)controller;
else
nav = controller.navigationController;
[nav.navigationBar addGestureRecognizer:panGesture];
[_gestures addObject:panGesture];
PP_RELEASE(panGesture);
}
if (interactions & PPRevealSideInteractionContentView) {
UIPanGestureRecognizer* panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureRecognizerDidPan:)];
panGesture.cancelsTouchesInView = YES;
panGesture.delegate = self;
UIViewController *c;
if ([controller isKindOfClass:[UINavigationController class]]) {
c = [((UINavigationController*)controller).viewControllers lastObject];
}
else
if (controller.navigationController)
c = [controller.navigationController.viewControllers lastObject];
else
c = controller;
[c.view addGestureRecognizer:panGesture];
[_gestures addObject:panGesture];
PP_RELEASE(panGesture);
}
}
- (void) addTapGestureToController:(UIViewController *)controller {
BOOL isClosed = ([self getSideToClose] == PPRevealSideDirectionNone) ? YES : NO;
if (isClosed)
{
// no tap gesture required when closed. So remove the old ones
[self removeAllTapGestures];
return;
}
if (_tapInteractionsWhenOpened & PPRevealSideInteractionNavigationBar && ([controller isKindOfClass:[UINavigationController class]] || controller.navigationController)) {
UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureRecognizerDidTap:)];
tapGesture.cancelsTouchesInView = YES;
tapGesture.delegate = self;
UINavigationController *nav;
if ([controller isKindOfClass:[UINavigationController class]])
nav = (UINavigationController*)controller;
else
nav = controller.navigationController;
[nav.navigationBar addGestureRecognizer:tapGesture];
[_gestures addObject:tapGesture];
PP_RELEASE(tapGesture);
}
if (_tapInteractionsWhenOpened & PPRevealSideInteractionContentView) {
UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(gestureRecognizerDidTap:)];
tapGesture.cancelsTouchesInView = YES;
tapGesture.delegate = self;
UIViewController *c;
if ([controller isKindOfClass:[UINavigationController class]]) {
c = [((UINavigationController*)controller).viewControllers lastObject];
}
else
if (controller.navigationController)
c = [controller.navigationController.viewControllers lastObject];
else
c = controller;
[c.view addGestureRecognizer:tapGesture];
[_gestures addObject:tapGesture];
PP_RELEASE(tapGesture);
}
}
- (void) addGesturesToController:(UIViewController*)controller {
[self removeAllGestures];
[self addPanGestureToController:controller];
[self addTapGestureToController:controller];
}
- (void) addGesturesToCenterController
{
[self addGesturesToController:[self getControllerForGestures]];
}
- (void) removeAllPanGestures {
NSMutableArray *array = [NSMutableArray arrayWithArray:_gestures];
for (UIGestureRecognizer* panGest in array) {
if ([panGest isKindOfClass:[UIPanGestureRecognizer class]]) {
[panGest.view removeGestureRecognizer:panGest];
[_gestures removeObject:panGest];
}
}
}
- (void) removeAllTapGestures {
NSMutableArray *array = [NSMutableArray arrayWithArray:_gestures];
for (UIGestureRecognizer* tapGest in array) {
if ([tapGest isKindOfClass:[UITapGestureRecognizer class]]) {
[tapGest.view removeGestureRecognizer:tapGest];
[_gestures removeObject:tapGest];
}
}
}
- (void) removeAllGestures {
for (UIGestureRecognizer* gest in _gestures) {
[gest.view removeGestureRecognizer:gest];
}
[_gestures removeAllObjects];
}
- (void) updateViewWhichHandleGestures
{
[self addGesturesToCenterController];
}
- (void) setOffset:(CGFloat)offset forDirection:(PPRevealSideDirection)direction
{
// This is always an offset for portrait
[_viewControllersOffsets setObject:[NSNumber numberWithFloat:offset] forKey:[NSNumber numberWithInt:direction]];
}
- (void) removeControllerFromView:(UIViewController*)controller animated:(BOOL)animated
{
if (PPSystemVersionGreaterOrEqualThan(5.0)) [controller willMoveToParentViewController:nil];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [controller viewWillDisappear:animated];
[controller.view removeFromSuperview];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [controller viewDidDisappear:animated];
if (PPSystemVersionGreaterOrEqualThan(5.0))
{
[controller removeFromParentViewController];
[controller didMoveToParentViewController:nil];
}
}
#pragma mark Closed Controllers
- (BOOL) isLeftControllerClosed {
return CGRectGetMinX(_rootViewController.view.frame) <= 0;
}
- (BOOL) isRightControllerClosed {
return CGRectGetMaxX(_rootViewController.view.frame) >= CGRectGetWidth(_rootViewController.view.frame);
}
- (BOOL) isTopControllerClosed {
return CGRectGetMinY(_rootViewController.view.frame) <= 0;
}
- (BOOL) isBottomControllerClosed {
return CGRectGetMaxY(_rootViewController.view.frame) >= CGRectGetHeight(_rootViewController.view.frame);
}
- (BOOL) isOptionEnabled:(PPRevealSideOptions)option {
return ((_options & option) == option);
}
- (BOOL) canCrossOffsets {
return ![self isOptionEnabled:PPRevealSideOptionsResizeSideView] && [self isOptionEnabled:PPRevealSideOptionsBounceAnimations];
}
- (PPRevealSideDirection) getSideToClose {
PPRevealSideDirection sideToReturn = PPRevealSideDirectionNone;
if (![self isRightControllerClosed]) sideToReturn = PPRevealSideDirectionRight;
if (![self isLeftControllerClosed]) sideToReturn = PPRevealSideDirectionLeft;
if (![self isTopControllerClosed]) sideToReturn = PPRevealSideDirectionTop;
if (![self isBottomControllerClosed]) sideToReturn = PPRevealSideDirectionBottom;
return sideToReturn;
}
- (CGRect) getSlidingRectForOffset:(CGFloat)offset forDirection:(PPRevealSideDirection)direction andOrientation:(UIInterfaceOrientation)orientation {
if (direction == PPRevealSideDirectionLeft || direction == PPRevealSideDirectionRight) offset = MIN(CGRectGetWidth(PPScreenBounds()), offset);
if (direction == PPRevealSideDirectionTop || direction == PPRevealSideDirectionBottom) offset = MIN(CGRectGetHeight(self.view.frame), offset);
CGRect rectToReturn = CGRectZero;
rectToReturn.size = _rootViewController.view.frame.size;
CGFloat width = CGRectGetWidth(_rootViewController.view.frame);
CGFloat height = CGRectGetHeight(_rootViewController.view.frame);
switch (direction) {
case PPRevealSideDirectionLeft:
rectToReturn.origin = CGPointMake(width-offset, 0.0);
break;
case PPRevealSideDirectionRight:
rectToReturn.origin = CGPointMake(-(width-offset), 0.0);
break;
case PPRevealSideDirectionBottom:
rectToReturn.origin = CGPointMake(0.0, -(height-offset));
break;
case PPRevealSideDirectionTop:
rectToReturn.origin = CGPointMake(0.0, height-offset);
break;
default:
break;
}
return rectToReturn;
}
- (CGRect) getSlidingRectForOffset:(CGFloat)offset forDirection:(PPRevealSideDirection)direction {
return [self getSlidingRectForOffset:offset forDirection:direction andOrientation:PPInterfaceOrientation()];
}
- (CGRect) getSideViewFrameFromRootFrame:(CGRect)rootFrame andDirection:(PPRevealSideDirection)direction {
CGRect slideFrame = CGRectZero;
CGFloat rootHeight = CGRectGetHeight(rootFrame);
CGFloat rootWidth = CGRectGetWidth(rootFrame);
if ([self isOptionEnabled:PPRevealSideOptionsResizeSideView]){
switch (direction) {
case PPRevealSideDirectionLeft:
slideFrame.size.height = rootHeight;
slideFrame.size.width = CGRectGetMinX(rootFrame);
break;
case PPRevealSideDirectionRight:
slideFrame.origin.x = CGRectGetMaxX(rootFrame);
slideFrame.size.height = rootHeight;
slideFrame.size.width = rootWidth - CGRectGetMaxX(rootFrame);
break;
case PPRevealSideDirectionTop:
slideFrame.size.height = CGRectGetMinY(rootFrame);
slideFrame.size.width = rootWidth;
break;
case PPRevealSideDirectionBottom:
slideFrame.origin.y = CGRectGetMaxY(rootFrame);
slideFrame.size.height = rootHeight-CGRectGetMaxY(rootFrame);
slideFrame.size.width = rootWidth;
break;
default:
break;
}
}
else
{
slideFrame.size.width = rootWidth;
slideFrame.size.height = rootHeight;
}
return slideFrame;
}
- (UIEdgeInsets) getEdgetInsetForDirection:(PPRevealSideDirection)direction {
UIEdgeInsets inset = UIEdgeInsetsZero;
if (![self isOptionEnabled:PPRevealSideOptionsResizeSideView]){
CGFloat offset = [self getOffsetForDirection:direction];
switch (direction) {
case PPRevealSideDirectionLeft:
inset.right = offset;
break;
case PPRevealSideDirectionRight:
inset.left = offset;
break;
case PPRevealSideDirectionTop:
inset.bottom = offset;
break;
case PPRevealSideDirectionBottom:
inset.top = offset;
break;
default:
break;
}
}
return inset;
}
- (CGFloat) getOffsetForDirection:(PPRevealSideDirection)direction andInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
CGFloat offset = [[_viewControllersOffsets objectForKey:[NSNumber numberWithInt:direction]] floatValue];
if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
if (![self isOptionEnabled:PPRevealSideOptionsKeepOffsetOnRotation])
{
// Take an orientation free rect
CGRect portraitBounds = [UIScreen mainScreen].bounds;
// Get the difference between width and height
CGFloat diff = 0.0;
if (direction == PPRevealSideDirectionLeft || direction == PPRevealSideDirectionRight)
diff = portraitBounds.size.height - portraitBounds.size.width;
if (direction == PPRevealSideDirectionTop)
diff = -(portraitBounds.size.height - portraitBounds.size.width);
// Store the offset + the diff
offset += diff;
}
}
return offset;
}
- (CGFloat) getOffsetForDirection:(PPRevealSideDirection)direction
{
return [self getOffsetForDirection:direction andInterfaceOrientation:PPInterfaceOrientation()];
}
#pragma mark - Gesture recognizer
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
_panOrigin = _rootViewController.view.frame.origin;
gestureRecognizer.enabled = YES;
_currentPanDirection = [self getSideToClose];
if (_currentPanDirection == PPRevealSideDirectionNone) _wasClosed = YES;
else _wasClosed = NO;
BOOL hasExceptionTouch = NO;
if ([touch.view isKindOfClass:[UIControl class]] && [gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
if (![touch.view isKindOfClass:NSClassFromString(@"UINavigationButton")]) hasExceptionTouch = YES;
}
BOOL hasExceptionDelegate = NO;
if ([self.delegate respondsToSelector:@selector(pprevealSideViewController:shouldDeactivateGesture:forView:)])
hasExceptionDelegate = [self.delegate pprevealSideViewController:self
shouldDeactivateGesture:gestureRecognizer
forView:touch.view];
if ([self.delegate respondsToSelector:@selector(pprevealSideViewController:directionsAllowedForPanningOnView:)]) {
_disabledPanGestureDirection = [self.delegate pprevealSideViewController:self directionsAllowedForPanningOnView:touch.view];
}
else
_disabledPanGestureDirection = PPRevealSideDirectionLeft | PPRevealSideDirectionRight | PPRevealSideDirectionTop | PPRevealSideDirectionBottom;
return !_animationInProgress && !hasExceptionTouch && !hasExceptionDelegate;
}
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
#define OFFSET_TRIGGER_CHOSE_DIRECTION 3.0
#define OFFSET_TRIGGER_CHANGE_DIRECTION 0.0
#define MAX_TRIGGER_OFFSET 100.0
- (void) gestureRecognizerDidPan:(UIPanGestureRecognizer*)panGesture {
if(_animationInProgress) return;
CGPoint currentPoint = [panGesture translationInView:self.view];
CGFloat x = currentPoint.x + _panOrigin.x;
CGFloat y = currentPoint.y + _panOrigin.y;
CGFloat offset = 0;
// if the center view controller is closed, then get the direction we want to Open
if (_currentPanDirection == PPRevealSideDirectionNone) {
CGFloat panDiffX = currentPoint.x - _panOrigin.x;
CGFloat panDiffY = currentPoint.y - _panOrigin.y;
if (panDiffX > 0 && panDiffX > OFFSET_TRIGGER_CHOSE_DIRECTION)
_currentPanDirection = PPRevealSideDirectionLeft;
else
if (panDiffX < 0 && panDiffX < OFFSET_TRIGGER_CHOSE_DIRECTION)
_currentPanDirection = PPRevealSideDirectionRight;
else
if (panDiffY > 0 && panDiffY > OFFSET_TRIGGER_CHOSE_DIRECTION)
_currentPanDirection = PPRevealSideDirectionTop;
else
if (panDiffY < 0 && panDiffY < OFFSET_TRIGGER_CHOSE_DIRECTION)
_currentPanDirection = PPRevealSideDirectionBottom;
}
if (_currentPanDirection == PPRevealSideDirectionNone) return;
// if the direction is disabled, then cancel the gesture
if ((_currentPanDirection & _disabledPanGestureDirection) != _currentPanDirection) {
// little trick to cancel the gesture. Otherwise, as long as we pan, we continue to pass here ...
panGesture.enabled = NO;
panGesture.enabled = YES;
return;
}
// see if there is a controller or not for the direction. If yes, then add it.
UIViewController *c = [_viewControllers objectForKey:[NSNumber numberWithInt:_currentPanDirection]];
if (c) {
if (!c.view.superview)
{
c.view.frame = self.rootViewController.view.bounds;
if (PPSystemVersionGreaterOrEqualThan(5.0))
{
[c willMoveToParentViewController:self];
[self addChildViewController:c];
}
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [c viewWillAppear:NO];
[self.view insertSubview:c.view belowSubview:_rootViewController.view];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [c viewDidAppear:NO];
if (PPSystemVersionGreaterOrEqualThan(5.0)) [self didMoveToParentViewController:self];
}
}
else // we use the bounce animation
{
PPRSLog(@"****** No controller to push ****** Think to preload controller ! ******");
[self pushOldViewControllerOnDirection:_currentPanDirection animated:YES];
// little trick to cancel the gesture. Otherwise, as long as we pan, we continue to pass here ...
panGesture.enabled = NO;
panGesture.enabled = YES;
return;
}
switch (_currentPanDirection) {
case PPRevealSideDirectionLeft:
offset = CGRectGetWidth(self.rootViewController.view.frame) - x;
break;
case PPRevealSideDirectionRight:
offset = x + CGRectGetWidth(self.rootViewController.view.frame);
break;
case PPRevealSideDirectionBottom:
offset = y + CGRectGetHeight(self.rootViewController.view.frame);
break;
case PPRevealSideDirectionTop:
offset = CGRectGetHeight(self.rootViewController.view.frame) - y;
break;
default:
break;
}
offset = MAX(offset, [self getOffsetForDirection:_currentPanDirection]);
// test if whe changed direction
if (_currentPanDirection == PPRevealSideDirectionRight || _currentPanDirection == PPRevealSideDirectionLeft) {
if (offset >= CGRectGetWidth(self.rootViewController.view.frame)-OFFSET_TRIGGER_CHANGE_DIRECTION) {
// change direction if possible
PPRevealSideDirection newDirection;
if (_currentPanDirection == PPRevealSideDirectionLeft)
newDirection = PPRevealSideDirectionRight;
else
newDirection = PPRevealSideDirectionLeft;
if ([_viewControllers objectForKey:[NSNumber numberWithInt:newDirection]]) {
UIViewController *c = [_viewControllers objectForKey:[NSNumber numberWithInt:_currentPanDirection]];
[self removeControllerFromView:c animated:YES];
_currentPanDirection = newDirection;
_wasClosed = !_wasClosed;
return;
}
}
}
else
{
if (offset >= CGRectGetHeight(self.rootViewController.view.frame) - OFFSET_TRIGGER_CHANGE_DIRECTION) {
// change direction if possible
PPRevealSideDirection newDirection;
if (_currentPanDirection == PPRevealSideDirectionBottom)
newDirection = PPRevealSideDirectionTop;
else
newDirection = PPRevealSideDirectionBottom;
if ([_viewControllers objectForKey:[NSNumber numberWithInt:newDirection]]) {
UIViewController *c = [_viewControllers objectForKey:[NSNumber numberWithInt:_currentPanDirection]];
[self removeControllerFromView:c animated:YES];
_currentPanDirection = newDirection;
_wasClosed = !_wasClosed;
return;
}
}
}
self.rootViewController.view.frame = [self getSlidingRectForOffset:offset
forDirection:_currentPanDirection];
if (panGesture.state == UIGestureRecognizerStateEnded || panGesture.state == UIGestureRecognizerStateCancelled) {
CGFloat offsetController = [self getOffsetForDirection:_currentPanDirection];
#define divisionNumber 5.0
CGFloat triggerStep;
if (_currentPanDirection == PPRevealSideDirectionLeft || _currentPanDirection == PPRevealSideDirectionRight)
triggerStep = (CGRectGetWidth(self.rootViewController.view.frame) - offsetController)/divisionNumber;
else
triggerStep = (CGRectGetHeight(self.rootViewController.view.frame) - offsetController)/divisionNumber;
BOOL shouldClose;
CGFloat sizeToTest;
CGFloat offsetTriggered;
// set a max trigger
triggerStep = MIN(triggerStep, MAX_TRIGGER_OFFSET);
if (_currentPanDirection == PPRevealSideDirectionLeft || _currentPanDirection == PPRevealSideDirectionRight)
{
sizeToTest = CGRectGetWidth(self.rootViewController.view.frame);
}
else
{
sizeToTest = CGRectGetHeight(self.rootViewController.view.frame);
}
if (_wasClosed)
{
offsetTriggered = sizeToTest - triggerStep;
}
else
{
offsetTriggered = triggerStep+offsetController;
}
//PPRSLog(@"offset %f ** sizeToTest %f ** triggerStep %f ** - %f", offset, sizeToTest, triggerStep, offsetTriggered);
if (offset > offsetTriggered)
shouldClose = YES;
else
shouldClose = NO;
if (shouldClose) {
_popFromPanGesture = YES;
[self popViewControllerAnimated:YES];
}
else
{
_shouldNotCloseWhenPushingSameDirection = YES;
[self pushOldViewControllerOnDirection:_currentPanDirection
withOffset:[self getOffsetForDirection:_currentPanDirection andInterfaceOrientation:UIInterfaceOrientationPortrait] // we get the interface orientation for Portrait since we set it just after.
animated:YES];
_shouldNotCloseWhenPushingSameDirection = NO;
}
}
}
- (void) gestureRecognizerDidTap:(UITapGestureRecognizer*)tapGesture {
PPRSLog(@"Yes, the tap gesture is animated, this is normal, not a bug! Is there anybody here with a non animate interface? :P");
[self popViewControllerAnimated:YES];
}
#pragma mark - Orientation stuff
- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [_rootViewController willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self resizeCurrentView];
for (id key in _viewControllers.allKeys)
{
UIViewController *controller = (UIViewController *)[_viewControllers objectForKey:key];
if (controller.view.superview) {
controller.view.frame = [self getSideViewFrameFromRootFrame:_rootViewController.view.frame
andDirection:[key intValue]];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [controller willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
}
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self removeShadow];
_rootViewController.view.layer.shouldRasterize = YES;
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [_rootViewController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
return;
for (id key in _viewControllers.allKeys)
{
// optimisation
UIViewController *controller = (UIViewController *)[_viewControllers objectForKey:key];
if (controller.view.superview && !PPSystemVersionGreaterOrEqualThan(5.0))
[controller willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
_rootViewController.view.layer.shouldRasterize = NO;
[self handleShadows];
if (!PPSystemVersionGreaterOrEqualThan(5.0)) [_rootViewController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
for (id key in _viewControllers.allKeys)
{
// optimisation
UIViewController *controller = (UIViewController *)[_viewControllers objectForKey:key];
if (controller.view.superview && !PPSystemVersionGreaterOrEqualThan(5.0))
[controller didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return [_rootViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
#pragma mark - Memory management things
- (void) viewWillUnload
{
[super viewWillUnload];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
@try {
[_rootViewController removeObserver:self forKeyPath:@"view.frame"];
}
@catch (NSException *exception) {
}
@finally {
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void) dealloc {
PP_RELEASE(_rootViewController);
PP_RELEASE(_viewControllers);
PP_RELEASE(_viewControllersOffsets);
[self removeAllGestures];
PP_RELEASE(_gestures);
#if !PP_ARC_ENABLED
[super dealloc];
#endif
}
@end
@implementation UIViewController (PPRevealSideViewController)
static char revealSideViewControllerKey;
- (void) setRevealSideViewController:(PPRevealSideViewController *)revealSideViewController {
[self willChangeValueForKey:@"revealSideViewController"];
objc_setAssociatedObject( self,
&revealSideViewControllerKey,
revealSideViewController,
OBJC_ASSOCIATION_RETAIN );
[self didChangeValueForKey:@"revealSideViewController"];
}
- (PPRevealSideViewController*) revealSideViewController {
id controller = objc_getAssociatedObject( self,
&revealSideViewControllerKey );
// because we can't ask the navigation controller to set to the pushed controller the revealSideViewController !
if (!controller && self.navigationController)
controller = self.navigationController.revealSideViewController;
return controller;
}
@end
@implementation UIView (PPRevealSideViewController)
static char revealSideInsetKey;
- (void) setRevealSideInset:(UIEdgeInsets)revealSideInset {
[self willChangeValueForKey:@"revealSideInset"];
NSString *stringInset = NSStringFromUIEdgeInsets(revealSideInset);
objc_setAssociatedObject( self,
&revealSideInsetKey,
stringInset,
OBJC_ASSOCIATION_RETAIN );
[self didChangeValueForKey:@"revealSideInset"];
}
- (UIEdgeInsets) revealSideInset {
NSString *stringInset = objc_getAssociatedObject( self,
&revealSideInsetKey );
UIEdgeInsets inset = UIEdgeInsetsZero;
if (stringInset)
inset = UIEdgeInsetsFromString(stringInset);
else
inset = self.superview.revealSideInset;
return inset;
}
@end
#pragma mark - Some Functions
UIInterfaceOrientation PPInterfaceOrientation(void) {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
return orientation;
}
CGRect PPScreenBounds(void) {
CGRect bounds = [UIScreen mainScreen].bounds;
if (UIInterfaceOrientationIsLandscape(PPInterfaceOrientation())) {
CGFloat width = bounds.size.width;
bounds.size.width = bounds.size.height;
bounds.size.height = width;
}
return bounds;
}
CGFloat PPStatusBarHeight(void) {
if ([[UIApplication sharedApplication] isStatusBarHidden]) return 0.0;
if (UIInterfaceOrientationIsLandscape(PPInterfaceOrientation()))
return [[UIApplication sharedApplication] statusBarFrame].size.width;
else
return [[UIApplication sharedApplication] statusBarFrame].size.height;
}