diff --git a/Classes/DeMarcelpociotSidemenuSideMenu.h b/Classes/DeMarcelpociotSidemenuSideMenu.h index daf7bff..7ac6fea 100644 --- a/Classes/DeMarcelpociotSidemenuSideMenu.h +++ b/Classes/DeMarcelpociotSidemenuSideMenu.h @@ -17,7 +17,8 @@ UIViewController * ControllerForProxy(TiViewProxy * proxy); } -(RESideMenu*)controller; --(void)presentMenuViewController:(id)args; +-(void)presentLeftMenuViewController:(id)args; +-(void)presentRightMenuViewController:(id)args; -(void)hideMenuViewController:(id)args; diff --git a/Classes/DeMarcelpociotSidemenuSideMenu.m b/Classes/DeMarcelpociotSidemenuSideMenu.m index 49a8605..30c757b 100644 --- a/Classes/DeMarcelpociotSidemenuSideMenu.m +++ b/Classes/DeMarcelpociotSidemenuSideMenu.m @@ -8,12 +8,13 @@ #import "DeMarcelpociotSidemenuSideMenu.h" #import "DeMarcelpociotSidemenuSideMenuProxy.h" #import "TiUtils.h" +#import "TiApp.h" #import "TiViewController.h" #import "TiUIiOSNavWindowProxy.h" -UIViewController * ControllerForViewProxy(TiViewProxy * proxy); +UIViewController * TiSideMenuControllerForViewProxy(TiViewProxy * proxy); -UIViewController * ControllerForViewProxy(TiViewProxy * proxy) +UIViewController * TiSideMenuControllerForViewProxy(TiViewProxy * proxy) { [[proxy view] setAutoresizingMask:UIViewAutoresizingNone]; @@ -26,7 +27,7 @@ return [[TiViewController alloc] initWithViewProxy:proxy]; } -UINavigationController * NavigationControllerForViewProxy(TiUIiOSNavWindowProxy *proxy) +UINavigationController * TiSideMenuNavigationControllerForViewProxy(TiUIiOSNavWindowProxy *proxy) { return [proxy controller]; } @@ -45,16 +46,41 @@ -(RESideMenu*)controller } // navController or TiWindow ? - UIViewController *centerWindow = useNavController ? NavigationControllerForViewProxy([self.proxy valueForUndefinedKey:@"contentView"]) : ControllerForViewProxy([self.proxy valueForUndefinedKey:@"contentView"]); + UIViewController *centerWindow = useNavController ? TiSideMenuNavigationControllerForViewProxy([self.proxy valueForUndefinedKey:@"contentView"]) : TiSideMenuControllerForViewProxy([self.proxy valueForUndefinedKey:@"contentView"]); - TiViewProxy *leftWindow = [self.proxy valueForUndefinedKey:@"menuView"]; - UIViewController *menuViewController = ControllerForViewProxy(leftWindow); + TiViewProxy *leftWindow = [self.proxy valueForUndefinedKey:@"leftMenuView"]; + TiViewProxy *rightWindow = [self.proxy valueForUndefinedKey:@"rightMenuView"]; + UIViewController *leftMenuViewController = TiSideMenuControllerForViewProxy(leftWindow); + UIViewController *rightMenuViewController = TiSideMenuControllerForViewProxy(rightWindow); - controller = [[RESideMenu alloc] initWithContentViewController:centerWindow - menuViewController:menuViewController]; + controller = [[RESideMenu alloc] initWithContentViewController:centerWindow + leftMenuViewController:leftMenuViewController + rightMenuViewController:rightMenuViewController]; - controller.backgroundImage = [TiUtils image:[self.proxy valueForUndefinedKey:@"backgroundImage"] proxy:self.proxy]; + bool blurView = [TiUtils boolValue:[self.proxy valueForUndefinedKey:@"blurBackground"] def:NO]; + UIImage *backgroundImageView = [TiUtils image:[self.proxy valueForUndefinedKey:@"backgroundImage"] proxy:self.proxy]; + controller.tintColor = [TiUtils colorValue:[self.proxy valueForUndefinedKey:@"tintColor"]].color; + controller.backgroundImage = backgroundImageView; + + // Check creation time parameters + // setContentViewScaleValue + [controller setContentViewScaleValue:[TiUtils floatValue:[self.proxy valueForUndefinedKey:@"contentViewScaleValue"] def:0.5]]; + + [controller setScaleContentView:[TiUtils boolValue:[self.proxy valueForUndefinedKey:@"scaleContentView"] def:YES]]; + + [controller setPanGestureEnabled:[TiUtils boolValue:[self.proxy valueForUndefinedKey:@"panGestureEnabled"] def:YES]]; + + [controller setLeftPanEnabled:[TiUtils boolValue:[self.proxy valueForUndefinedKey:@"leftPanEnabled"] def:YES]]; + + [controller setRightPanEnabled:[TiUtils boolValue:[self.proxy valueForUndefinedKey:@"rightPanEnabled"] def:YES]]; + + [controller setScaleBackgroundImageView:[TiUtils boolValue:[self.proxy valueForUndefinedKey:@"scaleBackgroundImageView"] def:YES]]; + + [controller setScaleMenuView:[TiUtils boolValue:[self.proxy valueForUndefinedKey:@"scaleMenuView"] def:YES]]; + + [controller setParallaxEnabled:[TiUtils boolValue:[self.proxy valueForUndefinedKey:@"parallaxEnabled"] def:YES]]; + UIView * controllerView = [controller view]; [controllerView setFrame:[self bounds]]; [self addSubview:controllerView]; @@ -77,19 +103,35 @@ -(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds -(void)setContentWindow_:(id)args { ENSURE_UI_THREAD(setContentWindow_, args); + id window; + BOOL animated = FALSE; + if( [args respondsToSelector:@selector(objectForKey:)] ) + { + window = [args objectForKey:@"window"]; + animated = [TiUtils boolValue:[args objectForKey:@"animated"] def:FALSE]; + } else { + window = args; + } BOOL useNavController = FALSE; - if([[[args class] description] isEqualToString:@"TiUIiOSNavWindowProxy"]) { + if([[[window class] description] isEqualToString:@"TiUIiOSNavWindowProxy"]) { useNavController = TRUE; } - UIViewController *centerWindow = useNavController ? NavigationControllerForViewProxy(args) : ControllerForViewProxy(args); - [controller setContentViewController:centerWindow]; + UIViewController *centerWindow = useNavController ? TiSideMenuNavigationControllerForViewProxy(window) : TiSideMenuControllerForViewProxy(window); + [controller setContentViewController:centerWindow animated:animated]; +} + +-(void)setLeftMenuWindow_:(id)args +{ + ENSURE_UI_THREAD(setLeftMenuWindow_, args); + ENSURE_SINGLE_ARG(args, TiViewProxy); + [controller setLeftMenuViewController:args]; } --(void)setMenuWindow_:(id)args +-(void)setRightMenuWindow_:(id)args { - ENSURE_UI_THREAD(setMenuWindow_, args); - ENSURE_SINGLE_ARG(args, TiViewProxy); - [controller setMenuViewController:args]; + ENSURE_UI_THREAD(setRightMenuWindow_, args); + ENSURE_SINGLE_ARG(args, TiViewProxy); + [controller setRightMenuViewController:args]; } -(void)setContentViewScaleValue_:(id)args @@ -110,23 +152,59 @@ -(void)setPanGestureEnabled_:(id)args [controller setPanGestureEnabled:[TiUtils boolValue:args]]; } +-(void)setPanFromEdge_:(id)args +{ + ENSURE_UI_THREAD(setPanFromEdge_, args); + [controller setPanFromEdge:[TiUtils boolValue:args]]; +} + +-(void)setMenuPrefersStatusBarHidden_:(id)args +{ + ENSURE_UI_THREAD(setMenuPrefersStatusBarHidden_, args); + [controller setMenuPrefersStatusBarHidden:[TiUtils boolValue:args]]; +} + + -(void)setScaleBackgroundImageView_:(id)args { ENSURE_UI_THREAD(setScaleBackgroundImageView_, args); [controller setScaleBackgroundImageView:[TiUtils boolValue:args]]; } +-(void)setScaleMenuView_:(id)args +{ + ENSURE_UI_THREAD(setScaleMenuView_, args); + [controller setScaleMenuView:[TiUtils boolValue:args]]; +} + -(void)setParallaxEnabled_:(id)args { ENSURE_UI_THREAD(setParallaxEnabled_, args); [controller setParallaxEnabled:[TiUtils boolValue:args]]; } +-(void)setLeftPanEnabled_:(id)args +{ + ENSURE_UI_THREAD(setLeftPanEnabled_, args); + [controller setLeftPanEnabled:[TiUtils boolValue:args]]; +} + +-(void)setRightPanEnabled_:(id)args +{ + ENSURE_UI_THREAD(setRightPanEnabled_, args); + [controller setRightPanEnabled:[TiUtils boolValue:args]]; +} + #pragma API --(void)presentMenuViewController:(id)args +-(void)presentLeftMenuViewController:(id)args +{ + ENSURE_UI_THREAD(presentLeftMenuViewController,args); + [controller presentLeftMenuViewController]; +} +-(void)presentRightMenuViewController:(id)args { - ENSURE_UI_THREAD(presentMenuViewController,args); - [controller presentMenuViewController]; + ENSURE_UI_THREAD(presentRightMenuViewController,args); + [controller presentRightMenuViewController]; } -(void)hideMenuViewController:(id)args diff --git a/Classes/DeMarcelpociotSidemenuSideMenuProxy.m b/Classes/DeMarcelpociotSidemenuSideMenuProxy.m index 6772dce..a57bdc9 100644 --- a/Classes/DeMarcelpociotSidemenuSideMenuProxy.m +++ b/Classes/DeMarcelpociotSidemenuSideMenuProxy.m @@ -12,6 +12,10 @@ @implementation DeMarcelpociotSidemenuSideMenuProxy +-(void)windowDidOpen { + [super windowDidOpen]; + [self reposition]; +} -(UIViewController *)_controller { return [(DeMarcelpociotSidemenuSideMenu*)[self view] controller]; @@ -23,8 +27,11 @@ -(TiUIView*)newView { # pragma API --(void)presentMenuViewController:(id)args { - TiThreadPerformOnMainThread(^{[(DeMarcelpociotSidemenuSideMenu*)[self view] presentMenuViewController:args];}, NO); +-(void)presentLeftMenuViewController:(id)args { + TiThreadPerformOnMainThread(^{[(DeMarcelpociotSidemenuSideMenu*)[self view] presentLeftMenuViewController:args];}, NO); +} +-(void)presentRightMenuViewController:(id)args { + TiThreadPerformOnMainThread(^{[(DeMarcelpociotSidemenuSideMenu*)[self view] presentRightMenuViewController:args];}, NO); } -(void)hideMenuViewController:(id)args { diff --git a/Classes/RESideMenu/RECommonFunctions.h b/Classes/RESideMenu/RECommonFunctions.h index e232ed2..0bc9c99 100755 --- a/Classes/RESideMenu/RECommonFunctions.h +++ b/Classes/RESideMenu/RECommonFunctions.h @@ -2,7 +2,7 @@ // RECommonFunctions.h // RESideMenu // -// Copyright (c) 2013 Roman Efimov (https://github.com/romaonthego) +// Copyright (c) 2013-2014 Roman Efimov (https://github.com/romaonthego) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,9 +25,9 @@ #import -#ifndef REUIKitIsFlatModeFunction -#define REUIKitIsFlatModeFunction -BOOL REUIKitIsFlatMode(); + +#ifndef REUIKitIsFlatMode +#define REUIKitIsFlatMode() RESideMenuUIKitIsFlatMode() #endif #ifndef kCFCoreFoundationVersionNumber_iOS_6_1 @@ -44,4 +44,4 @@ __VA_ARGS__ \ #define IF_IOS7_OR_GREATER(...) #endif -BOOL REDeviceIsUIKit7() __attribute__ ((deprecated)); \ No newline at end of file +BOOL RESideMenuUIKitIsFlatMode(void); \ No newline at end of file diff --git a/Classes/RESideMenu/RECommonFunctions.m b/Classes/RESideMenu/RECommonFunctions.m index b79da54..6924d66 100755 --- a/Classes/RESideMenu/RECommonFunctions.m +++ b/Classes/RESideMenu/RECommonFunctions.m @@ -2,7 +2,7 @@ // RECommonFunctions.m // RESideMenu // -// Copyright (c) 2013 Roman Efimov (https://github.com/romaonthego) +// Copyright (c) 2013-2014 Roman Efimov (https://github.com/romaonthego) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,12 +25,8 @@ #import "RECommonFunctions.h" #import -BOOL REDeviceIsUIKit7() -{ - return REUIKitIsFlatMode(); -} -BOOL REUIKitIsFlatMode() +BOOL RESideMenuUIKitIsFlatMode(void) { static BOOL isUIKitFlatMode = NO; static dispatch_once_t onceToken; diff --git a/Classes/RESideMenu/RESideMenu.h b/Classes/RESideMenu/RESideMenu.h index 7f45b47..bc5ac50 100755 --- a/Classes/RESideMenu/RESideMenu.h +++ b/Classes/RESideMenu/RESideMenu.h @@ -2,7 +2,7 @@ // REFrostedViewController.h // RESideMenu // -// Copyright (c) 2013 Roman Efimov (https://github.com/romaonthego) +// Copyright (c) 2013-2014 Roman Efimov (https://github.com/romaonthego) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,32 +26,66 @@ #import #import "UIViewController+RESideMenu.h" +#ifndef IBInspectable +#define IBInspectable +#endif + + @protocol RESideMenuDelegate; -@interface RESideMenu : UIViewController +@interface RESideMenu : UIViewController + +#if __IPHONE_8_0 +@property (strong, readwrite, nonatomic) IBInspectable NSString *contentViewStoryboardID; +@property (strong, readwrite, nonatomic) IBInspectable NSString *leftMenuViewStoryboardID; +@property (strong, readwrite, nonatomic) IBInspectable NSString *rightMenuViewStoryboardID; +#endif + +@property (strong, readwrite, nonatomic) UIViewController *contentViewController; +@property (strong, readwrite, nonatomic) UIViewController *leftMenuViewController; +@property (strong, readwrite, nonatomic) UIViewController *rightMenuViewController; +@property (weak, readwrite, nonatomic) id delegate; @property (assign, readwrite, nonatomic) NSTimeInterval animationDuration; @property (strong, readwrite, nonatomic) UIImage *backgroundImage; @property (assign, readwrite, nonatomic) BOOL panGestureEnabled; -@property (assign, readwrite, nonatomic) BOOL scaleContentView; -@property (assign, readwrite, nonatomic) BOOL scaleBackgroundImageView; -@property (assign, readwrite, nonatomic) CGFloat contentViewScaleValue; -@property (assign, readwrite, nonatomic) CGFloat contentViewInLandscapeOffsetCenterX; -@property (assign, readwrite, nonatomic) CGFloat contentViewInPortraitOffsetCenterX; -@property (strong, readwrite, nonatomic) id parallaxMenuMinimumRelativeValue; -@property (strong, readwrite, nonatomic) id parallaxMenuMaximumRelativeValue; -@property (strong, readwrite, nonatomic) id parallaxContentMinimumRelativeValue; -@property (strong, readwrite, nonatomic) id parallaxContentMaximumRelativeValue; -@property (assign, readwrite, nonatomic) BOOL parallaxEnabled; +@property (assign, readwrite, nonatomic) BOOL leftPanEnabled; +@property (assign, readwrite, nonatomic) BOOL rightPanEnabled; +@property (assign, readwrite, nonatomic) BOOL panFromEdge; +@property (assign, readwrite, nonatomic) NSUInteger panMinimumOpenThreshold; +@property (assign, readwrite, nonatomic) IBInspectable BOOL interactivePopGestureRecognizerEnabled; +@property (assign, readwrite, nonatomic) IBInspectable BOOL fadeMenuView; +@property (assign, readwrite, nonatomic) IBInspectable BOOL scaleContentView; +@property (assign, readwrite, nonatomic) IBInspectable BOOL scaleBackgroundImageView; +@property (assign, readwrite, nonatomic) IBInspectable BOOL scaleMenuView; +@property (assign, readwrite, nonatomic) IBInspectable BOOL contentViewShadowEnabled; +@property (strong, readwrite, nonatomic) IBInspectable UIColor *contentViewShadowColor; +@property (assign, readwrite, nonatomic) IBInspectable CGSize contentViewShadowOffset; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat contentViewShadowOpacity; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat contentViewShadowRadius; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat contentViewScaleValue; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat contentViewInLandscapeOffsetCenterX; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat contentViewInPortraitOffsetCenterX; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat parallaxMenuMinimumRelativeValue; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat parallaxMenuMaximumRelativeValue; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat parallaxContentMinimumRelativeValue; +@property (assign, readwrite, nonatomic) IBInspectable CGFloat parallaxContentMaximumRelativeValue; +@property (assign, readwrite, nonatomic) CGAffineTransform menuViewControllerTransformation; +@property (assign, readwrite, nonatomic) IBInspectable BOOL parallaxEnabled; +@property (assign, readwrite, nonatomic) IBInspectable BOOL bouncesHorizontally; +@property (assign, readwrite, nonatomic) UIStatusBarStyle menuPreferredStatusBarStyle; +@property (assign, readwrite, nonatomic) IBInspectable BOOL menuPrefersStatusBarHidden; -@property (strong, readwrite, nonatomic) UIViewController *contentViewController; -@property (strong, readwrite, nonatomic) UIViewController *menuViewController; +@property (assign, readwrite, nonatomic) UIColor *tintColor; -@property (weak, readwrite, nonatomic) id delegate; -- (id)initWithContentViewController:(UIViewController *)contentViewController menuViewController:(UIViewController *)menuViewController; -- (void)presentMenuViewController; +- (id)initWithContentViewController:(UIViewController *)contentViewController + leftMenuViewController:(UIViewController *)leftMenuViewController + rightMenuViewController:(UIViewController *)rightMenuViewController; +- (void)presentLeftMenuViewController; +- (void)presentRightMenuViewController; - (void)hideMenuViewController; +- (void)setContentViewController:(UIViewController *)contentViewController animated:(BOOL)animated; @end @@ -64,4 +98,4 @@ - (void)sideMenu:(RESideMenu *)sideMenu willHideMenuViewController:(UIViewController *)menuViewController; - (void)sideMenu:(RESideMenu *)sideMenu didHideMenuViewController:(UIViewController *)menuViewController; -@end \ No newline at end of file +@end diff --git a/Classes/RESideMenu/RESideMenu.m b/Classes/RESideMenu/RESideMenu.m index 9a12793..674bc1f 100755 --- a/Classes/RESideMenu/RESideMenu.m +++ b/Classes/RESideMenu/RESideMenu.m @@ -2,7 +2,7 @@ // REFrostedViewController.m // RESideMenu // -// Copyright (c) 2013 Roman Efimov (https://github.com/romaonthego) +// Copyright (c) 2013-2014 Roman Efimov (https://github.com/romaonthego) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,17 +27,26 @@ #import "UIViewController+RESideMenu.h" #import "RECommonFunctions.h" + @interface RESideMenu () @property (strong, readwrite, nonatomic) UIImageView *backgroundImageView; @property (assign, readwrite, nonatomic) BOOL visible; +@property (assign, readwrite, nonatomic) BOOL leftMenuVisible; +@property (assign, readwrite, nonatomic) BOOL rightMenuVisible; @property (assign, readwrite, nonatomic) CGPoint originalPoint; @property (strong, readwrite, nonatomic) UIButton *contentButton; +@property (strong, readwrite, nonatomic) UIView *menuViewContainer; +@property (strong, readwrite, nonatomic) UIView *contentViewContainer; +@property (assign, readwrite, nonatomic) BOOL didNotifyDelegate; @end @implementation RESideMenu +#pragma mark - +#pragma mark Instance lifecycle + - (id)init { self = [super init]; @@ -56,46 +65,127 @@ - (id)initWithCoder:(NSCoder *)decoder return self; } +#if __IPHONE_8_0 +- (void)awakeFromNib +{ + if (self.contentViewStoryboardID) { + self.contentViewController = [self.storyboard instantiateViewControllerWithIdentifier:self.contentViewStoryboardID]; + } + if (self.leftMenuViewStoryboardID) { + self.leftMenuViewController = [self.storyboard instantiateViewControllerWithIdentifier:self.leftMenuViewStoryboardID]; + } + if (self.rightMenuViewStoryboardID) { + self.rightMenuViewController = [self.storyboard instantiateViewControllerWithIdentifier:self.rightMenuViewStoryboardID]; + } +} +#endif + - (void)commonInit { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - self.wantsFullScreenLayout = YES; -#pragma clang diagnostic pop + _menuViewContainer = [[UIView alloc] init]; + _contentViewContainer = [[UIView alloc] init]; + _animationDuration = 0.35f; - _panGestureEnabled = YES; + _interactivePopGestureRecognizerEnabled = YES; - _scaleContentView = YES; - _contentViewScaleValue = 0.7f; + _menuViewControllerTransformation = CGAffineTransformMakeScale(1.5f, 1.5f); + _scaleContentView = YES; _scaleBackgroundImageView = YES; - + _scaleMenuView = YES; + + _fadeMenuView = YES; _parallaxEnabled = YES; - _parallaxMenuMinimumRelativeValue = @(-15); - _parallaxMenuMaximumRelativeValue = @(15); + _parallaxMenuMinimumRelativeValue = -15; + _parallaxMenuMaximumRelativeValue = 15; + _parallaxContentMinimumRelativeValue = -25; + _parallaxContentMaximumRelativeValue = 25; - _parallaxContentMinimumRelativeValue = @(-25); - _parallaxContentMaximumRelativeValue = @(25); + _bouncesHorizontally = YES; + + _panGestureEnabled = YES; + _leftPanEnabled = YES; + _rightPanEnabled = YES; + _panFromEdge = YES; + _panMinimumOpenThreshold = 60.0; + + _contentViewShadowEnabled = NO; + _contentViewShadowColor = [UIColor blackColor]; + _contentViewShadowOffset = CGSizeZero; + _contentViewShadowOpacity = 0.4f; + _contentViewShadowRadius = 8.0f; + _contentViewInLandscapeOffsetCenterX = 30.f; + _contentViewInPortraitOffsetCenterX = 30.f; + _contentViewScaleValue = 0.7f; } -- (id)initWithContentViewController:(UIViewController *)contentViewController menuViewController:(UIViewController *)menuViewController +#pragma mark - +#pragma mark Public methods + +- (id)initWithContentViewController:(UIViewController *)contentViewController leftMenuViewController:(UIViewController *)leftMenuViewController rightMenuViewController:(UIViewController *)rightMenuViewController { self = [self init]; if (self) { _contentViewController = contentViewController; - _menuViewController = menuViewController; + _leftMenuViewController = leftMenuViewController; + _rightMenuViewController = rightMenuViewController; } return self; } +- (void)presentLeftMenuViewController +{ + [self presentMenuViewContainerWithMenuViewController:self.leftMenuViewController]; + [self showLeftMenuViewController]; +} + +- (void)presentRightMenuViewController +{ + [self presentMenuViewContainerWithMenuViewController:self.rightMenuViewController]; + [self showRightMenuViewController]; +} + +- (void)hideMenuViewController +{ + [self hideMenuViewControllerAnimated:YES]; +} + +- (void)setContentViewController:(UIViewController *)contentViewController animated:(BOOL)animated +{ + if (_contentViewController == contentViewController) + { + return; + } + + if (!animated) { + [self setContentViewController:contentViewController]; + } else { + [self addChildViewController:contentViewController]; + contentViewController.view.alpha = 0; + contentViewController.view.frame = self.contentViewContainer.bounds; + [self.contentViewContainer addSubview:contentViewController.view]; + [UIView animateWithDuration:self.animationDuration animations:^{ + contentViewController.view.alpha = 1; + } completion:^(BOOL finished) { + [self hideViewController:self.contentViewController]; + [contentViewController didMoveToParentViewController:self]; + _contentViewController = contentViewController; + + [self statusBarNeedsAppearanceUpdate]; + [self updateContentViewShadow]; + + if (self.visible) { + [self addContentViewControllerMotionEffects]; + } + }]; + } +} + +#pragma mark View life cycle + - (void)viewDidLoad { [super viewDidLoad]; - if (!_contentViewInLandscapeOffsetCenterX) - _contentViewInLandscapeOffsetCenterX = CGRectGetHeight(self.view.frame) + 30.f; - - if (!_contentViewInPortraitOffsetCenterX) - _contentViewInPortraitOffsetCenterX = CGRectGetWidth(self.view.frame) + 30.f; self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.backgroundImageView = ({ @@ -112,143 +202,235 @@ - (void)viewDidLoad }); [self.view addSubview:self.backgroundImageView]; - [self re_displayController:self.menuViewController frame:self.view.frame]; - [self re_displayController:self.contentViewController frame:self.view.frame]; - self.menuViewController.view.alpha = 0; + [self.view addSubview:self.menuViewContainer]; + [self.view addSubview:self.contentViewContainer]; + + self.menuViewContainer.frame = self.view.bounds; + self.menuViewContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + if (self.leftMenuViewController) { + [self addChildViewController:self.leftMenuViewController]; + self.leftMenuViewController.view.frame = self.view.bounds; + self.leftMenuViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.menuViewContainer addSubview:self.leftMenuViewController.view]; + [self.leftMenuViewController didMoveToParentViewController:self]; + } + + if (self.rightMenuViewController) { + [self addChildViewController:self.rightMenuViewController]; + self.rightMenuViewController.view.frame = self.view.bounds; + self.rightMenuViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.menuViewContainer addSubview:self.rightMenuViewController.view]; + [self.rightMenuViewController didMoveToParentViewController:self]; + } + + self.contentViewContainer.frame = self.view.bounds; + self.contentViewContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + [self addChildViewController:self.contentViewController]; + self.contentViewController.view.frame = self.view.bounds; + [self.contentViewContainer addSubview:self.contentViewController.view]; + [self.contentViewController didMoveToParentViewController:self]; + + self.menuViewContainer.alpha = !self.fadeMenuView ?: 0; if (self.scaleBackgroundImageView) self.backgroundImageView.transform = CGAffineTransformMakeScale(1.7f, 1.7f); [self addMenuViewControllerMotionEffects]; if (self.panGestureEnabled) { + self.view.multipleTouchEnabled = NO; UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognized:)]; + panGestureRecognizer.delegate = self; [self.view addGestureRecognizer:panGestureRecognizer]; } -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - [self.contentViewController beginAppearanceTransition:YES animated:animated]; -} - -- (void)viewDidAppear:(BOOL)animated -{ - [super viewDidAppear:animated]; - [self.contentViewController endAppearanceTransition]; -} - -- (void)viewWillDisappear:(BOOL)animated -{ - [super viewWillDisappear:animated]; - [self.contentViewController beginAppearanceTransition:NO animated:animated]; -} - -- (void)viewDidDisappear:(BOOL)animated -{ - [super viewDidDisappear:animated]; - [self.contentViewController endAppearanceTransition]; + + [self updateContentViewShadow]; } #pragma mark - +#pragma mark Private methods -- (void)presentMenuViewController +- (void)presentMenuViewContainerWithMenuViewController:(UIViewController *)menuViewController { - self.menuViewController.view.transform = CGAffineTransformIdentity; + self.menuViewContainer.transform = CGAffineTransformIdentity; if (self.scaleBackgroundImageView) { self.backgroundImageView.transform = CGAffineTransformIdentity; self.backgroundImageView.frame = self.view.bounds; } - self.menuViewController.view.frame = self.view.bounds; - self.menuViewController.view.transform = CGAffineTransformMakeScale(1.5f, 1.5f); - self.menuViewController.view.alpha = 0; + self.menuViewContainer.frame = self.view.bounds; + if (self.scaleMenuView) { + self.menuViewContainer.transform = self.menuViewControllerTransformation; + } + self.menuViewContainer.alpha = !self.fadeMenuView ?: 0; if (self.scaleBackgroundImageView) self.backgroundImageView.transform = CGAffineTransformMakeScale(1.7f, 1.7f); if ([self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:willShowMenuViewController:)]) { - [self.delegate sideMenu:self willShowMenuViewController:self.menuViewController]; + [self.delegate sideMenu:self willShowMenuViewController:menuViewController]; } - - [self showMenuViewController]; } -- (void)showMenuViewController +- (void)showLeftMenuViewController { + if (!self.leftMenuViewController) { + return; + } + self.leftMenuViewController.view.hidden = NO; + self.rightMenuViewController.view.hidden = YES; [self.view.window endEditing:YES]; [self addContentButton]; - - if ([(UIGestureRecognizer*)self.view.gestureRecognizers.lastObject state] != UIGestureRecognizerStateEnded) { - [self.contentViewController beginAppearanceTransition:NO animated:YES]; - [self.menuViewController beginAppearanceTransition:YES animated:YES]; - } + [self updateContentViewShadow]; + [self resetContentViewScale]; [UIView animateWithDuration:self.animationDuration animations:^{ if (self.scaleContentView) { - self.contentViewController.view.transform = CGAffineTransformMakeScale(self.contentViewScaleValue, self.contentViewScaleValue); + self.contentViewContainer.transform = CGAffineTransformMakeScale(self.contentViewScaleValue, self.contentViewScaleValue); + } else { + self.contentViewContainer.transform = CGAffineTransformIdentity; } - self.contentViewController.view.center = CGPointMake((UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation) ? self.contentViewInLandscapeOffsetCenterX : self.contentViewInPortraitOffsetCenterX), self.contentViewController.view.center.y); - self.menuViewController.view.alpha = 1.0f; - self.menuViewController.view.transform = CGAffineTransformIdentity; + + if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) { + self.contentViewContainer.center = CGPointMake((UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? self.contentViewInLandscapeOffsetCenterX + CGRectGetWidth(self.view.frame) : self.contentViewInPortraitOffsetCenterX + CGRectGetWidth(self.view.frame)), self.contentViewContainer.center.y); + } else { + self.contentViewContainer.center = CGPointMake((UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? self.contentViewInLandscapeOffsetCenterX + CGRectGetHeight(self.view.frame) : self.contentViewInPortraitOffsetCenterX + CGRectGetWidth(self.view.frame)), self.contentViewContainer.center.y); + } + + self.menuViewContainer.alpha = !self.fadeMenuView ?: 1.0f; + + self.menuViewContainer.transform = CGAffineTransformIdentity; if (self.scaleBackgroundImageView) self.backgroundImageView.transform = CGAffineTransformIdentity; } completion:^(BOOL finished) { [self addContentViewControllerMotionEffects]; - [self.contentViewController endAppearanceTransition]; - [self.menuViewController endAppearanceTransition]; - if (!self.visible && [self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:didShowMenuViewController:)]) { - [self.delegate sideMenu:self didShowMenuViewController:self.menuViewController]; + [self.delegate sideMenu:self didShowMenuViewController:self.leftMenuViewController]; } self.visible = YES; + self.leftMenuVisible = YES; }]; - [self updateStatusBar]; + [self statusBarNeedsAppearanceUpdate]; } -- (void)hideMenuViewController +- (void)showRightMenuViewController { - if ([self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:willHideMenuViewController:)]) { - [self.delegate sideMenu:self willHideMenuViewController:self.menuViewController]; + if (!self.rightMenuViewController) { + return; } + self.leftMenuViewController.view.hidden = YES; + self.rightMenuViewController.view.hidden = NO; + [self.view.window endEditing:YES]; + [self addContentButton]; + [self updateContentViewShadow]; + [self resetContentViewScale]; - [self.contentButton removeFromSuperview]; + [[UIApplication sharedApplication] beginIgnoringInteractionEvents]; + [UIView animateWithDuration:self.animationDuration animations:^{ + if (self.scaleContentView) { + self.contentViewContainer.transform = CGAffineTransformMakeScale(self.contentViewScaleValue, self.contentViewScaleValue); + } else { + self.contentViewContainer.transform = CGAffineTransformIdentity; + } + self.contentViewContainer.center = CGPointMake((UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? -self.contentViewInLandscapeOffsetCenterX : -self.contentViewInPortraitOffsetCenterX), self.contentViewContainer.center.y); + + self.menuViewContainer.alpha = !self.fadeMenuView ?: 1.0f; + self.menuViewContainer.transform = CGAffineTransformIdentity; + if (self.scaleBackgroundImageView) + self.backgroundImageView.transform = CGAffineTransformIdentity; + + } completion:^(BOOL finished) { + if (!self.rightMenuVisible && [self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:didShowMenuViewController:)]) { + [self.delegate sideMenu:self didShowMenuViewController:self.rightMenuViewController]; + } + + self.visible = !(self.contentViewContainer.frame.size.width == self.view.bounds.size.width && self.contentViewContainer.frame.size.height == self.view.bounds.size.height && self.contentViewContainer.frame.origin.x == 0 && self.contentViewContainer.frame.origin.y == 0); + self.rightMenuVisible = self.visible; + [[UIApplication sharedApplication] endIgnoringInteractionEvents]; + [self addContentViewControllerMotionEffects]; + }]; - if ([(UIGestureRecognizer*)self.view.gestureRecognizers.lastObject state] != UIGestureRecognizerStateEnded) { - [self.menuViewController beginAppearanceTransition:NO animated:YES]; - [self.contentViewController beginAppearanceTransition:YES animated:YES]; + [self statusBarNeedsAppearanceUpdate]; +} + +- (void)resetContentViewScale +{ + CGAffineTransform t = self.contentViewContainer.transform; + CGFloat scale = sqrt(t.a * t.a + t.c * t.c); + CGRect frame = self.contentViewContainer.frame; + self.contentViewContainer.transform = CGAffineTransformIdentity; + self.contentViewContainer.transform = CGAffineTransformMakeScale(scale, scale); + self.contentViewContainer.frame = frame; +} + +- (void)hideViewController:(UIViewController *)viewController +{ + [viewController willMoveToParentViewController:nil]; + [viewController.view removeFromSuperview]; + [viewController removeFromParentViewController]; +} + +- (void)hideMenuViewControllerAnimated:(BOOL)animated +{ + BOOL rightMenuVisible = self.rightMenuVisible; + if ([self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:willHideMenuViewController:)]) { + [self.delegate sideMenu:self willHideMenuViewController:rightMenuVisible ? self.rightMenuViewController : self.leftMenuViewController]; } - [[UIApplication sharedApplication] beginIgnoringInteractionEvents]; - [UIView animateWithDuration:self.animationDuration animations:^{ - self.contentViewController.view.transform = CGAffineTransformIdentity; - self.contentViewController.view.frame = self.view.bounds; - self.menuViewController.view.transform = CGAffineTransformMakeScale(1.5f, 1.5f); - self.menuViewController.view.alpha = 0; - if (self.scaleBackgroundImageView) { - self.backgroundImageView.transform = CGAffineTransformMakeScale(1.7f, 1.7f); + self.visible = NO; + self.leftMenuVisible = NO; + self.rightMenuVisible = NO; + [self.contentButton removeFromSuperview]; + + __typeof (self) __weak weakSelf = self; + void (^animationBlock)(void) = ^{ + __typeof (weakSelf) __strong strongSelf = weakSelf; + if (!strongSelf) { + return; + } + strongSelf.contentViewContainer.transform = CGAffineTransformIdentity; + strongSelf.contentViewContainer.frame = strongSelf.view.bounds; + if (strongSelf.scaleMenuView) { + strongSelf.menuViewContainer.transform = strongSelf.menuViewControllerTransformation; + } + strongSelf.menuViewContainer.alpha = !self.fadeMenuView ?: 0; + if (strongSelf.scaleBackgroundImageView) { + strongSelf.backgroundImageView.transform = CGAffineTransformMakeScale(1.7f, 1.7f); } - if (self.parallaxEnabled) { + if (strongSelf.parallaxEnabled) { IF_IOS7_OR_GREATER( - for (UIMotionEffect *effect in self.contentViewController.view.motionEffects) { - [self.contentViewController.view removeMotionEffect:effect]; + for (UIMotionEffect *effect in strongSelf.contentViewContainer.motionEffects) { + [strongSelf.contentViewContainer removeMotionEffect:effect]; } ); } - } completion:^(BOOL finished) { - [[UIApplication sharedApplication] endIgnoringInteractionEvents]; - - [self.menuViewController endAppearanceTransition]; - [self.contentViewController endAppearanceTransition]; - - if (!self.visible && [self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:didHideMenuViewController:)]) { - [self.delegate sideMenu:self didHideMenuViewController:self.menuViewController]; + }; + void (^completionBlock)(void) = ^{ + __typeof (weakSelf) __strong strongSelf = weakSelf; + if (!strongSelf) { + return; } - }]; - self.visible = NO; - [self updateStatusBar]; + if (!strongSelf.visible && [strongSelf.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [strongSelf.delegate respondsToSelector:@selector(sideMenu:didHideMenuViewController:)]) { + [strongSelf.delegate sideMenu:strongSelf didHideMenuViewController:rightMenuVisible ? strongSelf.rightMenuViewController : strongSelf.leftMenuViewController]; + } + }; + + if (animated) { + [[UIApplication sharedApplication] beginIgnoringInteractionEvents]; + [UIView animateWithDuration:self.animationDuration animations:^{ + animationBlock(); + } completion:^(BOOL finished) { + [[UIApplication sharedApplication] endIgnoringInteractionEvents]; + completionBlock(); + }]; + } else { + animationBlock(); + completionBlock(); + } + [self statusBarNeedsAppearanceUpdate]; } - (void)addContentButton @@ -257,31 +439,53 @@ - (void)addContentButton return; self.contentButton.autoresizingMask = UIViewAutoresizingNone; - self.contentButton.frame = self.contentViewController.view.bounds; + self.contentButton.frame = self.contentViewContainer.bounds; self.contentButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self.contentViewController.view addSubview:self.contentButton]; + [self.contentViewContainer addSubview:self.contentButton]; +} + +- (void)statusBarNeedsAppearanceUpdate +{ + if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + [UIView animateWithDuration:0.3f animations:^{ + [self performSelector:@selector(setNeedsStatusBarAppearanceUpdate)]; + }]; + } +} + +- (void)updateContentViewShadow +{ + if (self.contentViewShadowEnabled) { + CALayer *layer = self.contentViewContainer.layer; + UIBezierPath *path = [UIBezierPath bezierPathWithRect:layer.bounds]; + layer.shadowPath = path.CGPath; + layer.shadowColor = self.contentViewShadowColor.CGColor; + layer.shadowOffset = self.contentViewShadowOffset; + layer.shadowOpacity = self.contentViewShadowOpacity; + layer.shadowRadius = self.contentViewShadowRadius; + } } #pragma mark - -#pragma mark Motion effects +#pragma mark iOS 7 Motion Effects (Private) - (void)addMenuViewControllerMotionEffects { if (self.parallaxEnabled) { IF_IOS7_OR_GREATER( - for (UIMotionEffect *effect in self.menuViewController.view.motionEffects) { - [self.menuViewController.view removeMotionEffect:effect]; + for (UIMotionEffect *effect in self.menuViewContainer.motionEffects) { + [self.menuViewContainer removeMotionEffect:effect]; } UIInterpolatingMotionEffect *interpolationHorizontal = [[UIInterpolatingMotionEffect alloc]initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis]; - interpolationHorizontal.minimumRelativeValue = self.parallaxMenuMinimumRelativeValue; - interpolationHorizontal.maximumRelativeValue = self.parallaxMenuMaximumRelativeValue; + interpolationHorizontal.minimumRelativeValue = @(self.parallaxMenuMinimumRelativeValue); + interpolationHorizontal.maximumRelativeValue = @(self.parallaxMenuMaximumRelativeValue); UIInterpolatingMotionEffect *interpolationVertical = [[UIInterpolatingMotionEffect alloc]initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis]; - interpolationVertical.minimumRelativeValue = self.parallaxMenuMinimumRelativeValue; - interpolationVertical.maximumRelativeValue = self.parallaxMenuMaximumRelativeValue; + interpolationVertical.minimumRelativeValue = @(self.parallaxMenuMinimumRelativeValue); + interpolationVertical.maximumRelativeValue = @(self.parallaxMenuMaximumRelativeValue); - [self.menuViewController.view addMotionEffect:interpolationHorizontal]; - [self.menuViewController.view addMotionEffect:interpolationVertical]; + [self.menuViewContainer addMotionEffect:interpolationHorizontal]; + [self.menuViewContainer addMotionEffect:interpolationVertical]; ); } } @@ -290,27 +494,53 @@ - (void)addContentViewControllerMotionEffects { if (self.parallaxEnabled) { IF_IOS7_OR_GREATER( - for (UIMotionEffect *effect in self.contentViewController.view.motionEffects) { - [self.contentViewController.view removeMotionEffect:effect]; + for (UIMotionEffect *effect in self.contentViewContainer.motionEffects) { + [self.contentViewContainer removeMotionEffect:effect]; } [UIView animateWithDuration:0.2 animations:^{ UIInterpolatingMotionEffect *interpolationHorizontal = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis]; - interpolationHorizontal.minimumRelativeValue = self.parallaxContentMinimumRelativeValue; - interpolationHorizontal.maximumRelativeValue = self.parallaxContentMaximumRelativeValue; + interpolationHorizontal.minimumRelativeValue = @(self.parallaxContentMinimumRelativeValue); + interpolationHorizontal.maximumRelativeValue = @(self.parallaxContentMaximumRelativeValue); UIInterpolatingMotionEffect *interpolationVertical = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis]; - interpolationVertical.minimumRelativeValue = self.parallaxContentMinimumRelativeValue; - interpolationVertical.maximumRelativeValue = self.parallaxContentMaximumRelativeValue; + interpolationVertical.minimumRelativeValue = @(self.parallaxContentMinimumRelativeValue); + interpolationVertical.maximumRelativeValue = @(self.parallaxContentMaximumRelativeValue); - [self.contentViewController.view addMotionEffect:interpolationHorizontal]; - [self.contentViewController.view addMotionEffect:interpolationVertical]; + [self.contentViewContainer addMotionEffect:interpolationHorizontal]; + [self.contentViewContainer addMotionEffect:interpolationVertical]; }]; ); } } #pragma mark - -#pragma mark Gesture recognizer +#pragma mark UIGestureRecognizer Delegate (Private) + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch +{ + IF_IOS7_OR_GREATER( + if (self.interactivePopGestureRecognizerEnabled && [self.contentViewController isKindOfClass:[UINavigationController class]]) { + UINavigationController *navigationController = (UINavigationController *)self.contentViewController; + if (navigationController.viewControllers.count > 1 && navigationController.interactivePopGestureRecognizer.enabled) { + return NO; + } + } + ); + + if (self.panFromEdge && [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && !self.visible) { + CGPoint point = [touch locationInView:gestureRecognizer.view]; + if (point.x < 20.0 || point.x > self.view.frame.size.width - 20.0) { + return YES; + } else { + return NO; + } + } + + return YES; +} + +#pragma mark - +#pragma mark Pan gesture recognizer (Private) - (void)panGestureRecognized:(UIPanGestureRecognizer *)recognizer { @@ -322,39 +552,59 @@ - (void)panGestureRecognized:(UIPanGestureRecognizer *)recognizer } CGPoint point = [recognizer translationInView:self.view]; + + if (point.x <= 0 && !self.rightPanEnabled && !self.leftMenuVisible) { + return; + } + if (point.x > 0 && !self.leftPanEnabled && !self.rightMenuVisible) { + return; + } if (recognizer.state == UIGestureRecognizerStateBegan) { + [self updateContentViewShadow]; - if (!self.visible && [self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:willShowMenuViewController:)]) { - [self.delegate sideMenu:self willShowMenuViewController:self.menuViewController]; - } - - self.originalPoint = self.contentViewController.view.frame.origin; - self.menuViewController.view.transform = CGAffineTransformIdentity; + self.originalPoint = CGPointMake(self.contentViewContainer.center.x - CGRectGetWidth(self.contentViewContainer.bounds) / 2.0, + self.contentViewContainer.center.y - CGRectGetHeight(self.contentViewContainer.bounds) / 2.0); + self.menuViewContainer.transform = CGAffineTransformIdentity; if (self.scaleBackgroundImageView) { self.backgroundImageView.transform = CGAffineTransformIdentity; self.backgroundImageView.frame = self.view.bounds; } - self.menuViewController.view.frame = self.view.bounds; + self.menuViewContainer.frame = self.view.bounds; [self addContentButton]; [self.view.window endEditing:YES]; - - [self.contentViewController beginAppearanceTransition:self.visible animated:YES]; - [self.menuViewController beginAppearanceTransition:!self.visible animated:YES]; + self.didNotifyDelegate = NO; } - if (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged) { - CGFloat delta = self.visible ? (point.x + self.originalPoint.x) / self.originalPoint.x : point.x / self.view.frame.size.width; + if (recognizer.state == UIGestureRecognizerStateChanged) { + CGFloat delta = 0; + if (self.visible) { + delta = self.originalPoint.x != 0 ? (point.x + self.originalPoint.x) / self.originalPoint.x : 0; + } else { + delta = point.x / self.view.frame.size.width; + } + delta = MIN(fabs(delta), 1.6); CGFloat contentViewScale = self.scaleContentView ? 1 - ((1 - self.contentViewScaleValue) * delta) : 1; + CGFloat backgroundViewScale = 1.7f - (0.7f * delta); CGFloat menuViewScale = 1.5f - (0.5f * delta); + + if (!self.bouncesHorizontally) { + contentViewScale = MAX(contentViewScale, self.contentViewScaleValue); + backgroundViewScale = MAX(backgroundViewScale, 1.0); + menuViewScale = MAX(menuViewScale, 1.0); + } + + self.menuViewContainer.alpha = !self.fadeMenuView ?: delta; - self.menuViewController.view.alpha = delta; if (self.scaleBackgroundImageView) { self.backgroundImageView.transform = CGAffineTransformMakeScale(backgroundViewScale, backgroundViewScale); } - self.menuViewController.view.transform = CGAffineTransformMakeScale(menuViewScale, menuViewScale); + + if (self.scaleMenuView) { + self.menuViewContainer.transform = CGAffineTransformMakeScale(menuViewScale, menuViewScale); + } if (self.scaleBackgroundImageView) { if (backgroundViewScale < 1) { @@ -362,25 +612,94 @@ - (void)panGestureRecognized:(UIPanGestureRecognizer *)recognizer } } - if (contentViewScale > 1) { - if (!self.visible) { - self.contentViewController.view.transform = CGAffineTransformIdentity; + if (!self.bouncesHorizontally && self.visible) { + if (self.contentViewContainer.frame.origin.x > self.contentViewContainer.frame.size.width / 2.0) + point.x = MIN(0.0, point.x); + + if (self.contentViewContainer.frame.origin.x < -(self.contentViewContainer.frame.size.width / 2.0)) + point.x = MAX(0.0, point.x); + } + + // Limit size + // + if (point.x < 0) { + point.x = MAX(point.x, -[UIScreen mainScreen].bounds.size.height); + } else { + point.x = MIN(point.x, [UIScreen mainScreen].bounds.size.height); + } + [recognizer setTranslation:point inView:self.view]; + + if (!self.didNotifyDelegate) { + if (point.x > 0) { + if (!self.visible && [self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:willShowMenuViewController:)]) { + [self.delegate sideMenu:self willShowMenuViewController:self.leftMenuViewController]; + } + } + if (point.x < 0) { + if (!self.visible && [self.delegate conformsToProtocol:@protocol(RESideMenuDelegate)] && [self.delegate respondsToSelector:@selector(sideMenu:willShowMenuViewController:)]) { + [self.delegate sideMenu:self willShowMenuViewController:self.rightMenuViewController]; + } } - self.contentViewController.view.frame = self.view.bounds; + self.didNotifyDelegate = YES; + } + + if (contentViewScale > 1) { + CGFloat oppositeScale = (1 - (contentViewScale - 1)); + self.contentViewContainer.transform = CGAffineTransformMakeScale(oppositeScale, oppositeScale); + self.contentViewContainer.transform = CGAffineTransformTranslate(self.contentViewContainer.transform, point.x, 0); } else { - self.contentViewController.view.transform = CGAffineTransformMakeScale(contentViewScale, contentViewScale); - self.contentViewController.view.transform = CGAffineTransformTranslate(self.contentViewController.view.transform, self.visible ? point.x * 0.8 : point.x, 0); + self.contentViewContainer.transform = CGAffineTransformMakeScale(contentViewScale, contentViewScale); + self.contentViewContainer.transform = CGAffineTransformTranslate(self.contentViewContainer.transform, point.x, 0); } - [self updateStatusBar]; + self.leftMenuViewController.view.hidden = self.contentViewContainer.frame.origin.x < 0; + self.rightMenuViewController.view.hidden = self.contentViewContainer.frame.origin.x > 0; + + if (!self.leftMenuViewController && self.contentViewContainer.frame.origin.x > 0) { + self.contentViewContainer.transform = CGAffineTransformIdentity; + self.contentViewContainer.frame = self.view.bounds; + self.visible = NO; + self.leftMenuVisible = NO; + } else if (!self.rightMenuViewController && self.contentViewContainer.frame.origin.x < 0) { + self.contentViewContainer.transform = CGAffineTransformIdentity; + self.contentViewContainer.frame = self.view.bounds; + self.visible = NO; + self.rightMenuVisible = NO; + } + + [self statusBarNeedsAppearanceUpdate]; } - if (recognizer.state == UIGestureRecognizerStateEnded) { - if ([recognizer velocityInView:self.view].x > 0) { - [self showMenuViewController]; - } else { + if (recognizer.state == UIGestureRecognizerStateEnded) { + self.didNotifyDelegate = NO; + if (self.panMinimumOpenThreshold > 0 && ( + (self.contentViewContainer.frame.origin.x < 0 && self.contentViewContainer.frame.origin.x > -((NSInteger)self.panMinimumOpenThreshold)) || + (self.contentViewContainer.frame.origin.x > 0 && self.contentViewContainer.frame.origin.x < self.panMinimumOpenThreshold)) + ) { [self hideMenuViewController]; } + else if (self.contentViewContainer.frame.origin.x == 0) { + [self hideMenuViewControllerAnimated:NO]; + } + else { + if ([recognizer velocityInView:self.view].x > 0) { + if (self.contentViewContainer.frame.origin.x < 0) { + [self hideMenuViewController]; + } else { + if (self.leftMenuViewController) { + [self showLeftMenuViewController]; + } + } + } else { + if (self.contentViewContainer.frame.origin.x < 20) { + if (self.rightMenuViewController) { + [self showRightMenuViewController]; + } + } else { + [self hideMenuViewController]; + } + } + } } } @@ -400,61 +719,107 @@ - (void)setContentViewController:(UIViewController *)contentViewController _contentViewController = contentViewController; return; } - CGRect frame = _contentViewController.view.frame; - CGAffineTransform transform = _contentViewController.view.transform; - [self re_hideController:_contentViewController]; + [self hideViewController:_contentViewController]; _contentViewController = contentViewController; - [self re_displayController:contentViewController frame:self.view.frame]; - contentViewController.view.transform = transform; - contentViewController.view.frame = frame; - [self addContentViewControllerMotionEffects]; + [self addChildViewController:self.contentViewController]; + self.contentViewController.view.frame = self.view.bounds; + [self.contentViewContainer addSubview:self.contentViewController.view]; + [self.contentViewController didMoveToParentViewController:self]; + + [self updateContentViewShadow]; + + if (self.visible) { + [self addContentViewControllerMotionEffects]; + } +} + +- (void)setLeftMenuViewController:(UIViewController *)leftMenuViewController +{ + if (!_leftMenuViewController) { + _leftMenuViewController = leftMenuViewController; + return; + } + [self hideViewController:_leftMenuViewController]; + _leftMenuViewController = leftMenuViewController; + + [self addChildViewController:self.leftMenuViewController]; + self.leftMenuViewController.view.frame = self.view.bounds; + self.leftMenuViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.menuViewContainer addSubview:self.leftMenuViewController.view]; + [self.leftMenuViewController didMoveToParentViewController:self]; + + [self addMenuViewControllerMotionEffects]; + [self.view bringSubviewToFront:self.contentViewContainer]; } -- (void)setMenuViewController:(UIViewController *)menuViewController +- (void)setRightMenuViewController:(UIViewController *)rightMenuViewController { - if (!_menuViewController) { - _menuViewController = menuViewController; + if (!_rightMenuViewController) { + _rightMenuViewController = rightMenuViewController; return; } - [self re_hideController:_menuViewController]; - _menuViewController = menuViewController; - [self re_displayController:menuViewController frame:self.view.frame]; + [self hideViewController:_rightMenuViewController]; + _rightMenuViewController = rightMenuViewController; + + [self addChildViewController:self.rightMenuViewController]; + self.rightMenuViewController.view.frame = self.view.bounds; + self.rightMenuViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.menuViewContainer addSubview:self.rightMenuViewController.view]; + [self.rightMenuViewController didMoveToParentViewController:self]; [self addMenuViewControllerMotionEffects]; - [self.view bringSubviewToFront:self.contentViewController.view]; + [self.view bringSubviewToFront:self.contentViewContainer]; } #pragma mark - -#pragma mark Rotation handler +#pragma mark View Controller Rotation handler - (BOOL)shouldAutorotate { - if (self.visible) - return NO; - return self.contentViewController.shouldAutorotate; } -#pragma mark - -#pragma mark Status bar appearance management - -- (void)updateStatusBar +- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { - [UIView animateWithDuration:0.3f animations:^{ - [self performSelector:@selector(setNeedsStatusBarAppearanceUpdate)]; - }]; + if (self.visible) { + self.menuViewContainer.bounds = self.view.bounds; + self.contentViewContainer.transform = CGAffineTransformIdentity; + self.contentViewContainer.frame = self.view.bounds; + + if (self.scaleContentView) { + self.contentViewContainer.transform = CGAffineTransformMakeScale(self.contentViewScaleValue, self.contentViewScaleValue); + } else { + self.contentViewContainer.transform = CGAffineTransformIdentity; + } + + CGPoint center; + if (self.leftMenuVisible) { + if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) { + center = CGPointMake((UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation) ? self.contentViewInLandscapeOffsetCenterX + CGRectGetWidth(self.view.frame) : self.contentViewInPortraitOffsetCenterX + CGRectGetWidth(self.view.frame)), self.contentViewContainer.center.y); + } else { + center = CGPointMake((UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation) ? self.contentViewInLandscapeOffsetCenterX + CGRectGetHeight(self.view.frame) : self.contentViewInPortraitOffsetCenterX + CGRectGetWidth(self.view.frame)), self.contentViewContainer.center.y); + } + } else { + center = CGPointMake((UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation) ? -self.contentViewInLandscapeOffsetCenterX : -self.contentViewInPortraitOffsetCenterX), self.contentViewContainer.center.y); + } + + self.contentViewContainer.center = center; } + + [self updateContentViewShadow]; } +#pragma mark - +#pragma mark Status Bar Appearance Management + - (UIStatusBarStyle)preferredStatusBarStyle { UIStatusBarStyle statusBarStyle = UIStatusBarStyleDefault; IF_IOS7_OR_GREATER( - statusBarStyle = self.visible ? self.menuViewController.preferredStatusBarStyle : self.contentViewController.preferredStatusBarStyle; - if (self.contentViewController.view.frame.origin.y > 10) { - statusBarStyle = self.menuViewController.preferredStatusBarStyle; + statusBarStyle = self.visible ? self.menuPreferredStatusBarStyle : self.contentViewController.preferredStatusBarStyle; + if (self.contentViewContainer.frame.origin.y > 10) { + statusBarStyle = self.menuPreferredStatusBarStyle; } else { statusBarStyle = self.contentViewController.preferredStatusBarStyle; } @@ -466,9 +831,9 @@ - (BOOL)prefersStatusBarHidden { BOOL statusBarHidden = NO; IF_IOS7_OR_GREATER( - statusBarHidden = self.visible ? self.menuViewController.prefersStatusBarHidden : self.contentViewController.prefersStatusBarHidden; - if (self.contentViewController.view.frame.origin.y > 10) { - statusBarHidden = self.menuViewController.prefersStatusBarHidden; + statusBarHidden = self.visible ? self.menuPrefersStatusBarHidden : self.contentViewController.prefersStatusBarHidden; + if (self.contentViewContainer.frame.origin.y > 10) { + statusBarHidden = self.menuPrefersStatusBarHidden; } else { statusBarHidden = self.contentViewController.prefersStatusBarHidden; } @@ -480,9 +845,9 @@ - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { UIStatusBarAnimation statusBarAnimation = UIStatusBarAnimationNone; IF_IOS7_OR_GREATER( - statusBarAnimation = self.visible ? self.menuViewController.preferredStatusBarUpdateAnimation : self.contentViewController.preferredStatusBarUpdateAnimation; - if (self.contentViewController.view.frame.origin.y > 10) { - statusBarAnimation = self.menuViewController.preferredStatusBarUpdateAnimation; + statusBarAnimation = self.visible ? self.leftMenuViewController.preferredStatusBarUpdateAnimation : self.contentViewController.preferredStatusBarUpdateAnimation; + if (self.contentViewContainer.frame.origin.y > 10) { + statusBarAnimation = self.leftMenuViewController.preferredStatusBarUpdateAnimation; } else { statusBarAnimation = self.contentViewController.preferredStatusBarUpdateAnimation; } diff --git a/Classes/RESideMenu/UIViewController+RESideMenu.h b/Classes/RESideMenu/UIViewController+RESideMenu.h index 2963bf1..ac46ca6 100755 --- a/Classes/RESideMenu/UIViewController+RESideMenu.h +++ b/Classes/RESideMenu/UIViewController+RESideMenu.h @@ -2,7 +2,7 @@ // UIViewController+RESideMenu.h // RESideMenu // -// Copyright (c) 2013 Roman Efimov (https://github.com/romaonthego) +// Copyright (c) 2013-2014 Roman Efimov (https://github.com/romaonthego) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,9 @@ @property (strong, readonly, nonatomic) RESideMenu *sideMenuViewController; -- (void)re_displayController:(UIViewController *)controller frame:(CGRect)frame; -- (void)re_hideController:(UIViewController *)controller; +// IB Action Helper methods + +- (IBAction)presentLeftMenuViewController:(id)sender; +- (IBAction)presentRightMenuViewController:(id)sender; @end diff --git a/Classes/RESideMenu/UIViewController+RESideMenu.m b/Classes/RESideMenu/UIViewController+RESideMenu.m index 7229117..46d0e8f 100755 --- a/Classes/RESideMenu/UIViewController+RESideMenu.m +++ b/Classes/RESideMenu/UIViewController+RESideMenu.m @@ -2,7 +2,7 @@ // UIViewController+RESideMenu.m // RESideMenu // -// Copyright (c) 2013 Roman Efimov (https://github.com/romaonthego) +// Copyright (c) 2013-2014 Roman Efimov (https://github.com/romaonthego) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,22 +26,7 @@ #import "UIViewController+RESideMenu.h" #import "RESideMenu.h" -@implementation UIViewController (REFrostedViewController) - -- (void)re_displayController:(UIViewController *)controller frame:(CGRect)frame -{ - [self addChildViewController:controller]; - controller.view.frame = frame; - [self.view addSubview:controller.view]; - [controller didMoveToParentViewController:self]; -} - -- (void)re_hideController:(UIViewController *)controller -{ - [controller willMoveToParentViewController:nil]; - [controller.view removeFromSuperview]; - [controller removeFromParentViewController]; -} +@implementation UIViewController (RESideMenu) - (RESideMenu *)sideMenuViewController { @@ -58,4 +43,17 @@ - (RESideMenu *)sideMenuViewController return nil; } +#pragma mark - +#pragma mark IB Action Helper methods + +- (IBAction)presentLeftMenuViewController:(id)sender +{ + [self.sideMenuViewController presentLeftMenuViewController]; +} + +- (IBAction)presentRightMenuViewController:(id)sender +{ + [self.sideMenuViewController presentRightMenuViewController]; +} + @end diff --git a/Demo.gif b/Demo.gif index 4d3fae2..025acf2 100755 Binary files a/Demo.gif and b/Demo.gif differ diff --git a/FXBlurView/FXBlurView.h b/FXBlurView/FXBlurView.h new file mode 100755 index 0000000..babce98 --- /dev/null +++ b/FXBlurView/FXBlurView.h @@ -0,0 +1,58 @@ +// +// FXBlurView.h +// +// Version 1.4.3 +// +// Created by Nick Lockwood on 25/08/2013. +// Copyright (c) 2013 Charcoal Design +// +// Distributed under the permissive zlib License +// Get the latest version from here: +// +// https://github.com/nicklockwood/FXBlurView +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + + +#import +#import + + +@interface UIImage (FXBlurView) + +- (UIImage *)blurredImageWithRadius:(CGFloat)radius iterations:(NSUInteger)iterations tintColor:(UIColor *)tintColor; + +@end + + +@interface FXBlurView : UIView + ++ (void)setBlurEnabled:(BOOL)blurEnabled; ++ (void)setUpdatesEnabled; ++ (void)setUpdatesDisabled; + +@property (nonatomic, getter = isBlurEnabled) BOOL blurEnabled; +@property (nonatomic, getter = isDynamic) BOOL dynamic; +@property (nonatomic, assign) NSUInteger iterations; +@property (nonatomic, assign) NSTimeInterval updateInterval; +@property (nonatomic, assign) CGFloat blurRadius; +@property (nonatomic, strong) UIColor *tintColor; + +@end diff --git a/FXBlurView/FXBlurView.m b/FXBlurView/FXBlurView.m new file mode 100755 index 0000000..55adc59 --- /dev/null +++ b/FXBlurView/FXBlurView.m @@ -0,0 +1,472 @@ +// +// FXBlurView.m +// +// Version 1.4.3 +// +// Created by Nick Lockwood on 25/08/2013. +// Copyright (c) 2013 Charcoal Design +// +// Distributed under the permissive zlib License +// Get the latest version from here: +// +// https://github.com/nicklockwood/FXBlurView +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + + +#import "FXBlurView.h" +#import +#import +#import + + +#import +#if !__has_feature(objc_arc) +#error This class requires automatic reference counting +#endif + + +@implementation UIImage (FXBlurView) + +- (UIImage *)blurredImageWithRadius:(CGFloat)radius iterations:(NSUInteger)iterations tintColor:(UIColor *)tintColor +{ + //image must be nonzero size + if (floorf(self.size.width) * floorf(self.size.height) <= 0.0f) return self; + + //boxsize must be an odd integer + uint32_t boxSize = radius * self.scale; + if (boxSize % 2 == 0) boxSize ++; + + //create image buffers + CGImageRef imageRef = self.CGImage; + vImage_Buffer buffer1, buffer2; + buffer1.width = buffer2.width = CGImageGetWidth(imageRef); + buffer1.height = buffer2.height = CGImageGetHeight(imageRef); + buffer1.rowBytes = buffer2.rowBytes = CGImageGetBytesPerRow(imageRef); + CFIndex bytes = buffer1.rowBytes * buffer1.height; + buffer1.data = malloc(bytes); + buffer2.data = malloc(bytes); + + //create temp buffer + void *tempBuffer = malloc(vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, NULL, 0, 0, boxSize, boxSize, + NULL, kvImageEdgeExtend + kvImageGetTempBufferSize)); + + //copy image data + CFDataRef dataSource = CGDataProviderCopyData(CGImageGetDataProvider(imageRef)); + memcpy(buffer1.data, CFDataGetBytePtr(dataSource), bytes); + CFRelease(dataSource); + + for (NSUInteger i = 0; i < iterations; i++) + { + //perform blur + vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, tempBuffer, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend); + + //swap buffers + void *temp = buffer1.data; + buffer1.data = buffer2.data; + buffer2.data = temp; + } + + //free buffers + free(buffer2.data); + free(tempBuffer); + + //create image context from buffer + CGContextRef ctx = CGBitmapContextCreate(buffer1.data, buffer1.width, buffer1.height, + 8, buffer1.rowBytes, CGImageGetColorSpace(imageRef), + CGImageGetBitmapInfo(imageRef)); + + //apply tint + if (tintColor && CGColorGetAlpha(tintColor.CGColor) > 0.0f) + { + CGContextSetFillColorWithColor(ctx, [tintColor colorWithAlphaComponent:0.25].CGColor); + CGContextSetBlendMode(ctx, kCGBlendModePlusLighter); + CGContextFillRect(ctx, CGRectMake(0, 0, buffer1.width, buffer1.height)); + } + + //create image from context + imageRef = CGBitmapContextCreateImage(ctx); + UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; + CGImageRelease(imageRef); + CGContextRelease(ctx); + free(buffer1.data); + return image; +} + +@end + + +@interface FXBlurScheduler : NSObject + +@property (nonatomic, strong) NSMutableArray *views; +@property (nonatomic, assign) NSInteger viewIndex; +@property (nonatomic, assign) NSInteger updatesEnabled; +@property (nonatomic, assign) BOOL blurEnabled; +@property (nonatomic, assign) BOOL updating; + +@end + + +@interface FXBlurView () + +@property (nonatomic, assign) BOOL iterationsSet; +@property (nonatomic, assign) BOOL blurRadiusSet; +@property (nonatomic, assign) BOOL dynamicSet; +@property (nonatomic, assign) BOOL blurEnabledSet; +@property (nonatomic, strong) NSDate *lastUpdate; + +- (UIImage *)snapshotOfSuperview:(UIView *)superview; + +@end + + +@implementation FXBlurScheduler + ++ (instancetype)sharedInstance +{ + static FXBlurScheduler *sharedInstance = nil; + if (!sharedInstance) + { + sharedInstance = [[FXBlurScheduler alloc] init]; + } + return sharedInstance; +} + +- (instancetype)init +{ + if (self = [super init]) + { + _updatesEnabled = 1; + _blurEnabled = YES; + _views = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)setBlurEnabled:(BOOL)blurEnabled +{ + _blurEnabled = blurEnabled; + if (blurEnabled) + { + for (FXBlurView *view in self.views) + { + [view setNeedsDisplay]; + } + [self updateAsynchronously]; + } +} + +- (void)setUpdatesEnabled +{ + _updatesEnabled ++; + [self updateAsynchronously]; +} + +- (void)setUpdatesDisabled +{ + _updatesEnabled --; +} + +- (void)addView:(FXBlurView *)view +{ + if (![self.views containsObject:view]) + { + [self.views addObject:view]; + [self updateAsynchronously]; + } +} + +- (void)removeView:(FXBlurView *)view +{ + NSInteger index = [self.views indexOfObject:view]; + if (index != NSNotFound) + { + if (index <= self.viewIndex) + { + self.viewIndex --; + } + [self.views removeObjectAtIndex:index]; + } +} + +- (void)updateAsynchronously +{ + if (self.blurEnabled && !self.updating && self.updatesEnabled > 0 && [self.views count]) + { + //loop through until we find a view that's ready to be drawn + self.viewIndex = self.viewIndex % [self.views count]; + for (NSUInteger i = self.viewIndex; i < [self.views count]; i++) + { + FXBlurView *view = self.views[i]; + if (view.blurEnabled && view.dynamic && view.window && + (!view.lastUpdate || [view.lastUpdate timeIntervalSinceNow] < -view.updateInterval) && + !CGRectIsEmpty(view.bounds) && !CGRectIsEmpty(view.superview.bounds)) + { + self.updating = YES; + UIImage *snapshot = [view snapshotOfSuperview:view.superview]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ + + UIImage *blurredImage = [snapshot blurredImageWithRadius:view.blurRadius + iterations:view.iterations + tintColor:view.tintColor]; + dispatch_sync(dispatch_get_main_queue(), ^{ + + //set image + self.updating = NO; + if (view.dynamic) + { + view.layer.contents = (id)blurredImage.CGImage; + view.layer.contentsScale = blurredImage.scale; + } + + //render next view + self.viewIndex = i + 1; + [self performSelectorOnMainThread:@selector(updateAsynchronously) withObject:nil + waitUntilDone:NO modes:@[NSDefaultRunLoopMode, UITrackingRunLoopMode]]; + }); + }); + return; + } + } + + //try again + self.viewIndex = 0; + [self performSelectorOnMainThread:@selector(updateAsynchronously) withObject:nil + waitUntilDone:NO modes:@[NSDefaultRunLoopMode, UITrackingRunLoopMode]]; + } +} + +@end + + +@implementation FXBlurView + ++ (void)setBlurEnabled:(BOOL)blurEnabled +{ + [FXBlurScheduler sharedInstance].blurEnabled = blurEnabled; +} + ++ (void)setUpdatesEnabled +{ + [[FXBlurScheduler sharedInstance] setUpdatesEnabled]; +} + ++ (void)setUpdatesDisabled +{ + [[FXBlurScheduler sharedInstance] setUpdatesDisabled]; +} + +- (void)setUp +{ + if (!_iterationsSet) _iterations = 3; + if (!_blurRadiusSet) _blurRadius = 40.0f; + if (!_dynamicSet) _dynamic = YES; + if (!_blurEnabledSet) _blurEnabled = YES; + self.updateInterval = _updateInterval; + + unsigned int numberOfMethods; + Method *methods = class_copyMethodList([UIView class], &numberOfMethods); + for (unsigned int i = 0; i < numberOfMethods; i++) + { + Method method = methods[i]; + SEL selector = method_getName(method); + if (selector == @selector(tintColor)) + { + _tintColor = ((id (*)(id,SEL))method_getImplementation(method))(self, selector); + break; + } + } + free(methods); +} + +- (id)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) + { + [self setUp]; + self.clipsToBounds = YES; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + if ((self = [super initWithCoder:aDecoder])) + { + [self setUp]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)setIterations:(NSUInteger)iterations +{ + _iterationsSet = YES; + _iterations = iterations; + [self setNeedsDisplay]; +} + +- (void)setBlurRadius:(CGFloat)blurRadius +{ + _blurRadiusSet = YES; + _blurRadius = blurRadius; + [self setNeedsDisplay]; +} + +- (void)setBlurEnabled:(BOOL)blurEnabled +{ + _blurEnabledSet = YES; + if (_blurEnabled != blurEnabled) + { + _blurEnabled = blurEnabled; + [self schedule]; + if (_blurEnabled) + { + [self setNeedsDisplay]; + } + } +} + +- (void)setDynamic:(BOOL)dynamic +{ + _dynamicSet = YES; + if (_dynamic != dynamic) + { + _dynamic = dynamic; + [self schedule]; + if (!dynamic) + { + [self setNeedsDisplay]; + } + } +} + +- (void)setUpdateInterval:(NSTimeInterval)updateInterval +{ + _updateInterval = updateInterval; + if (_updateInterval <= 0) _updateInterval = 1.0/60; +} + +- (void)setTintColor:(UIColor *)tintColor +{ + _tintColor = tintColor; + [self setNeedsDisplay]; +} + +- (void)didMoveToSuperview +{ + [super didMoveToSuperview]; + [self.layer setNeedsDisplay]; +} + +- (void)didMoveToWindow +{ + [super didMoveToWindow]; + [self schedule]; +} + +- (void)schedule +{ + if (self.window && self.dynamic && self.blurEnabled) + { + [[FXBlurScheduler sharedInstance] addView:self]; + } + else + { + [[FXBlurScheduler sharedInstance] removeView:self]; + } +} + +- (void)setNeedsDisplay +{ + [super setNeedsDisplay]; + [self.layer setNeedsDisplay]; +} + +- (void)displayLayer:(__unused CALayer *)layer +{ + if ([FXBlurScheduler sharedInstance].blurEnabled && self.blurEnabled && self.superview && + !CGRectIsEmpty(self.bounds) && !CGRectIsEmpty(self.superview.bounds)) + { + UIImage *snapshot = [self snapshotOfSuperview:self.superview]; + UIImage *blurredImage = [snapshot blurredImageWithRadius:self.blurRadius + iterations:self.iterations + tintColor:self.tintColor]; + self.layer.contents = (id)blurredImage.CGImage; + self.layer.contentsScale = blurredImage.scale; + } +} + +- (UIImage *)snapshotOfSuperview:(UIView *)superview +{ + self.lastUpdate = [NSDate date]; + CGFloat scale = 0.5; + if (self.iterations > 0 && ([UIScreen mainScreen].scale > 1 || self.contentMode == UIViewContentModeScaleAspectFill)) + { + CGFloat blockSize = 12.0f/self.iterations; + scale = blockSize/MAX(blockSize * 2, floor(self.blurRadius)); + } + CGSize size = self.bounds.size; + size.width = ceilf(size.width * scale) / scale; + size.height = ceilf(size.height * scale) / scale; + UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, scale); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextTranslateCTM(context, -self.frame.origin.x, -self.frame.origin.y); + CGContextScaleCTM(context, size.width / self.bounds.size.width, size.height / self.bounds.size.height); + NSArray *hiddenViews = [self prepareSuperviewForSnapshot:superview]; + [superview.layer renderInContext:context]; + [self restoreSuperviewAfterSnapshot:hiddenViews]; + UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return snapshot; +} + +- (NSArray *)prepareSuperviewForSnapshot:(UIView *)superview +{ + NSMutableArray *views = [NSMutableArray array]; + NSInteger index = [superview.subviews indexOfObject:self]; + if (index != NSNotFound) + { + for (NSUInteger i = index; i < [superview.subviews count]; i++) + { + UIView *view = superview.subviews[i]; + if (!view.hidden) + { + view.hidden = YES; + [views addObject:view]; + } + } + } + return views; +} + +- (void)restoreSuperviewAfterSnapshot:(NSArray *)hiddenViews +{ + for (UIView *view in hiddenViews) + { + view.hidden = NO; + } +} + +@end diff --git a/README.md b/README.md index d476e61..b59f2fe 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,18 @@ TiSideMenu =========================================== -** iOS 7 ONLY ** +** iOS 7 / 8 ONLY ** -iOS 7 style side menu with parallax effect. +iOS 7 / 8 style side menu with parallax effect. Wrapper module for the great [RESideMenu](https://github.com/romaonthego/RESideMenu) -RESideMenu Screenshot +Since 1.2 this module supports both left and right menu views. -Usage -==================== + +RESideMenu Screenshot + +### Usage Use TiSideMenu as a replacement for your root window. @@ -18,29 +20,76 @@ Use TiSideMenu as a replacement for your root window. background: 'red' }); - var menuView = Ti.UI.createWindow({ + var leftMenuView = Ti.UI.createWindow({ + background: 'transparent' + }); + var rightMenuView = Ti.UI.createWindow({ background: 'transparent' }); var win = TiSideMenu.createSideMenu({ contentView: contentView, - menuView: menuView, - backgroundImage: 'stars.png' + leftMenuView: leftMenuView, + rightMenuView: rightMenuView, + backgroundImage: 'stars.png', + contentViewScaleValue: 0.2, + scaleContentView: true, + panGestureEnabled: false, + scaleBackgroundImageView: false, + scaleMenuView: true, + parallaxEnabled: false, + panFromEdge: true, }); win.open(); + +### Replacing the content window -Configuration -=== +* Setting the content window without animation `Default` + + win.setContentWindow(newWin); + +* Setting the content window with an animation + + win.setContentWindow({ + window: newWin, + animated: true + }); + +### Alloy + +To use this module within Alloy, please take a look at this repository: [de.marcelpociot.alloysidemenu](https://github.com/manumaticx/de.marcelpociot.alloysidemenu) + + +### Known issues +If the slide animation is enabled, a bug exists where an incomplete slide results in opening empty windows through a navigation / tabgroup. +To resolve this issue be sure to manually hide the side Menu before opening the new window. + +`win.hideMenuViewController();` + + +### Configuration * Enable / Disable the pan gesture `win.setPanGestureEnabled( true / false );` + +* Enable / Disable pan from left + `win.setLeftPanEnabled( true / false );` + +* Enable / Disable pan from right + `win.setRightPanEnabled( true / false );` +* Enable / Disable then pan from the edge + `win.setPanFromEdge( true / false ); ` + * Enable / Disable Parallax effect `win.setParallaxEnabled( true / false ); ` * Enable / Disable Background image scaling `win.setScaleBackgroundImageView( true / false );` +* Enable / Disable menu view scaling + `win.setScaleMenuView( true / false );` + * Enable / Disable Content view scaling `win.setScaleContentView( true / false );` @@ -51,7 +100,85 @@ Manually showing / hiding the menu: `win.hideMenuViewController()` -`win.presentMenuViewController()` +`win.presentLeftMenuViewController()` + +`win.presentRightMenuViewController()` + +### Options + + +#### backgroundImage + +Type: `Blog / Image URL` +Default: `empty String` + +Background image to use for the menu. + +#### contentViewScaleValue + +Type: `Float` +Default: `0.5` + +Scale value used for the content view when the menu is shown. + +#### scaleContentView + +Type: `Boolean` +Default: `true` + +Should the content view be scaled when the menu gets displayed. + + +#### panGestureEnabled + +Type: `Boolean` +Default: `true` + +Should the pan gesture be available for showing the menu. + +#### leftPanEnabled + +Type: `Boolean` +Default: `true` + +Enable / Disable pan from left. + +#### rightPanEnabled + +Type: `Boolean` +Default: `true` + +Enable / Disable pan from right. + +#### panFromEdge + +Type: `Boolean` +Default: `false` + +Should the pan gesture only trigger when it starts from the edge + +#### scaleBackgroundImageView + +Type: `Boolean` +Default: `true` + +Should the background image view be scaled for showing the menu. + +#### scaleMenuView + +Type: `Boolean` +Default: `true` + +Should the menu view be scaled as it is made visible. + +#### parallaxEnabled + +Type: `Boolean` +Default: `true` + +Enable / disable the parallax effect. + + Events === @@ -78,9 +205,23 @@ Events }); +Changelog +=== +#### 2.0 +* Added iOS 8 support +* Removed the build-in blur APIs as they where crushing the battery +* Updated to the latest RESideMenu Version + +#### 1.2 +* Added support for left and right menu views + ABOUT THE AUTHOR ======================== I'm a web enthusiast located in Germany. -Follow me on twitter: @marcelpociot \ No newline at end of file +Follow me on twitter: @marcelpociot + + +[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/mpociot/tisidemenu/trend.png)](https://bitdeli.com/free "Bitdeli Badge") + diff --git a/TiSideMenu.xcodeproj/project.pbxproj b/TiSideMenu.xcodeproj/project.pbxproj index ab6ffc0..a94c32b 100644 --- a/TiSideMenu.xcodeproj/project.pbxproj +++ b/TiSideMenu.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 45; + objectVersion = 46; objects = { /* Begin PBXAggregateTarget section */ @@ -22,6 +22,8 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 1E9D41C618283C7F00BFEAE8 /* FXBlurView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E9D41C418283C7F00BFEAE8 /* FXBlurView.h */; }; + 1E9D41C718283C7F00BFEAE8 /* FXBlurView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E9D41C518283C7F00BFEAE8 /* FXBlurView.m */; }; 1EA8BECD181C66B700880B36 /* RECommonFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EA8BEC7181C66B700880B36 /* RECommonFunctions.h */; }; 1EA8BECE181C66B700880B36 /* RECommonFunctions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EA8BEC8181C66B700880B36 /* RECommonFunctions.m */; }; 1EA8BECF181C66B700880B36 /* RESideMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EA8BEC9181C66B700880B36 /* RESideMenu.h */; }; @@ -32,6 +34,9 @@ 1EA8BED6181C689B00880B36 /* DeMarcelpociotSidemenuSideMenuProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EA8BED4181C689B00880B36 /* DeMarcelpociotSidemenuSideMenuProxy.m */; }; 1EA8BED9181C68AD00880B36 /* DeMarcelpociotSidemenuSideMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EA8BED7181C68AD00880B36 /* DeMarcelpociotSidemenuSideMenu.h */; }; 1EA8BEDA181C68AD00880B36 /* DeMarcelpociotSidemenuSideMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EA8BED8181C68AD00880B36 /* DeMarcelpociotSidemenuSideMenu.m */; }; + 1EF4025B19E5E67E00DC7692 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EF4025A19E5E67E00DC7692 /* QuartzCore.framework */; }; + 1EF4025D19E5E68300DC7692 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EF4025C19E5E68300DC7692 /* Accelerate.framework */; }; + 1EF4025F19E5E68800DC7692 /* CoreImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EF4025E19E5E68800DC7692 /* CoreImage.framework */; }; 24DD6CF91134B3F500162E58 /* DeMarcelpociotSidemenuModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DD6CF71134B3F500162E58 /* DeMarcelpociotSidemenuModule.h */; }; 24DD6CFA1134B3F500162E58 /* DeMarcelpociotSidemenuModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 24DD6CF81134B3F500162E58 /* DeMarcelpociotSidemenuModule.m */; }; 24DE9E1111C5FE74003F90F6 /* DeMarcelpociotSidemenuModuleAssets.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DE9E0F11C5FE74003F90F6 /* DeMarcelpociotSidemenuModuleAssets.h */; }; @@ -51,6 +56,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 1E9D41C418283C7F00BFEAE8 /* FXBlurView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FXBlurView.h; sourceTree = ""; }; + 1E9D41C518283C7F00BFEAE8 /* FXBlurView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FXBlurView.m; sourceTree = ""; }; 1EA8BEC7181C66B700880B36 /* RECommonFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RECommonFunctions.h; sourceTree = ""; }; 1EA8BEC8181C66B700880B36 /* RECommonFunctions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RECommonFunctions.m; sourceTree = ""; }; 1EA8BEC9181C66B700880B36 /* RESideMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RESideMenu.h; sourceTree = ""; }; @@ -61,6 +68,9 @@ 1EA8BED4181C689B00880B36 /* DeMarcelpociotSidemenuSideMenuProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeMarcelpociotSidemenuSideMenuProxy.m; path = Classes/DeMarcelpociotSidemenuSideMenuProxy.m; sourceTree = ""; }; 1EA8BED7181C68AD00880B36 /* DeMarcelpociotSidemenuSideMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeMarcelpociotSidemenuSideMenu.h; path = Classes/DeMarcelpociotSidemenuSideMenu.h; sourceTree = ""; }; 1EA8BED8181C68AD00880B36 /* DeMarcelpociotSidemenuSideMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeMarcelpociotSidemenuSideMenu.m; path = Classes/DeMarcelpociotSidemenuSideMenu.m; sourceTree = ""; }; + 1EF4025A19E5E67E00DC7692 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 1EF4025C19E5E68300DC7692 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; + 1EF4025E19E5E68800DC7692 /* CoreImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; }; 24DD6CF71134B3F500162E58 /* DeMarcelpociotSidemenuModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeMarcelpociotSidemenuModule.h; path = Classes/DeMarcelpociotSidemenuModule.h; sourceTree = ""; }; 24DD6CF81134B3F500162E58 /* DeMarcelpociotSidemenuModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeMarcelpociotSidemenuModule.m; path = Classes/DeMarcelpociotSidemenuModule.m; sourceTree = ""; }; 24DD6D1B1134B66800162E58 /* titanium.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = titanium.xcconfig; sourceTree = ""; }; @@ -76,6 +86,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1EF4025F19E5E68800DC7692 /* CoreImage.framework in Frameworks */, + 1EF4025D19E5E68300DC7692 /* Accelerate.framework in Frameworks */, + 1EF4025B19E5E67E00DC7692 /* QuartzCore.framework in Frameworks */, AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -105,6 +118,9 @@ 0867D69AFE84028FC02AAC07 /* Frameworks */ = { isa = PBXGroup; children = ( + 1EF4025E19E5E68800DC7692 /* CoreImage.framework */, + 1EF4025C19E5E68300DC7692 /* Accelerate.framework */, + 1EF4025A19E5E67E00DC7692 /* QuartzCore.framework */, AACBBE490F95108600F1A2B1 /* Foundation.framework */, ); name = Frameworks; @@ -113,6 +129,7 @@ 08FB77AEFE84172EC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 1E9D41C318283C7F00BFEAE8 /* FXBlurView */, 1EA8BEC6181C66B700880B36 /* RESideMenu */, 24DE9E0F11C5FE74003F90F6 /* DeMarcelpociotSidemenuModuleAssets.h */, 24DE9E1011C5FE74003F90F6 /* DeMarcelpociotSidemenuModuleAssets.m */, @@ -126,6 +143,15 @@ name = Classes; sourceTree = ""; }; + 1E9D41C318283C7F00BFEAE8 /* FXBlurView */ = { + isa = PBXGroup; + children = ( + 1E9D41C418283C7F00BFEAE8 /* FXBlurView.h */, + 1E9D41C518283C7F00BFEAE8 /* FXBlurView.m */, + ); + path = FXBlurView; + sourceTree = ""; + }; 1EA8BEC6181C66B700880B36 /* RESideMenu */ = { isa = PBXGroup; children = ( @@ -163,6 +189,7 @@ 1EA8BED1181C66B700880B36 /* UIViewController+RESideMenu.h in Headers */, 1EA8BECD181C66B700880B36 /* RECommonFunctions.h in Headers */, 1EA8BECF181C66B700880B36 /* RESideMenu.h in Headers */, + 1E9D41C618283C7F00BFEAE8 /* FXBlurView.h in Headers */, 24DE9E1111C5FE74003F90F6 /* DeMarcelpociotSidemenuModuleAssets.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -193,9 +220,10 @@ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { + LastUpgradeCheck = 0600; }; buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "TiSideMenu" */; - compatibilityVersion = "Xcode 3.1"; + compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( @@ -241,6 +269,7 @@ 24DD6CFA1134B3F500162E58 /* DeMarcelpociotSidemenuModule.m in Sources */, 1EA8BED2181C66B700880B36 /* UIViewController+RESideMenu.m in Sources */, 1EA8BECE181C66B700880B36 /* RECommonFunctions.m in Sources */, + 1E9D41C718283C7F00BFEAE8 /* FXBlurView.m in Sources */, 24DE9E1211C5FE74003F90F6 /* DeMarcelpociotSidemenuModuleAssets.m in Sources */, 1EA8BED6181C689B00880B36 /* DeMarcelpociotSidemenuSideMenuProxy.m in Sources */, ); @@ -281,6 +310,7 @@ GCC_WARN_UNUSED_VALUE = NO; GCC_WARN_UNUSED_VARIABLE = NO; INSTALL_PATH = /usr/local/lib; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LIBRARY_SEARCH_PATHS = ""; OTHER_CFLAGS = ( "-DDEBUG", @@ -319,7 +349,7 @@ GCC_WARN_UNUSED_VALUE = NO; GCC_WARN_UNUSED_VARIABLE = NO; INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LIBRARY_SEARCH_PATHS = ""; OTHER_CFLAGS = "-DTI_POST_1_2"; OTHER_LDFLAGS = "-ObjC"; @@ -353,6 +383,8 @@ GCC_WARN_UNUSED_VALUE = NO; GCC_WARN_UNUSED_VARIABLE = NO; INSTALL_PATH = /usr/local/lib; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( "-DDEBUG", "-DTI_POST_1_2", @@ -389,7 +421,7 @@ GCC_WARN_UNUSED_VALUE = NO; GCC_WARN_UNUSED_VARIABLE = NO; INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; OTHER_CFLAGS = "-DTI_POST_1_2"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = DeMarcelpociotSidemenu; @@ -406,6 +438,7 @@ COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; PRODUCT_NAME = "Build & test"; }; name = Debug; @@ -417,6 +450,7 @@ COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_FIX_AND_CONTINUE = NO; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; PRODUCT_NAME = "Build & test"; ZERO_LINK = NO; }; diff --git a/TiSideMenu.xcodeproj/project.xcworkspace/xcshareddata/TiSideMenu.xccheckout b/TiSideMenu.xcodeproj/project.xcworkspace/xcshareddata/TiSideMenu.xccheckout index 7065dc4..8648dda 100644 --- a/TiSideMenu.xcodeproj/project.xcworkspace/xcshareddata/TiSideMenu.xccheckout +++ b/TiSideMenu.xcodeproj/project.xcworkspace/xcshareddata/TiSideMenu.xccheckout @@ -5,34 +5,34 @@ IDESourceControlProjectFavoriteDictionaryKey IDESourceControlProjectIdentifier - D008AB45-EBDC-484F-9B37-E8EDD10FE4F0 + 12C60D2F-4D88-46A3-8C62-2FE051DA982F IDESourceControlProjectName TiSideMenu IDESourceControlProjectOriginsDictionary - 571B9698-F150-4025-A81A-0153F02A7070 - ssh://github.com/mpociot/TiSideMenu.git + 762DA8BD60B7A5B61218D312214DCEA723E36090 + github.com:mpociot/TiSideMenu.git IDESourceControlProjectPath - TiSideMenu.xcodeproj/project.xcworkspace + TiSideMenu.xcodeproj IDESourceControlProjectRelativeInstallPathDictionary - 571B9698-F150-4025-A81A-0153F02A7070 + 762DA8BD60B7A5B61218D312214DCEA723E36090 ../.. IDESourceControlProjectURL - ssh://github.com/mpociot/TiSideMenu.git + github.com:mpociot/TiSideMenu.git IDESourceControlProjectVersion - 110 + 111 IDESourceControlProjectWCCIdentifier - 571B9698-F150-4025-A81A-0153F02A7070 + 762DA8BD60B7A5B61218D312214DCEA723E36090 IDESourceControlProjectWCConfigurations IDESourceControlRepositoryExtensionIdentifierKey public.vcs.git IDESourceControlWCCIdentifierKey - 571B9698-F150-4025-A81A-0153F02A7070 + 762DA8BD60B7A5B61218D312214DCEA723E36090 IDESourceControlWCCName TiSideMenu diff --git a/TiSideMenu.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/UserInterfaceState.xcuserstate b/TiSideMenu.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/UserInterfaceState.xcuserstate index 9f7f6a2..994a9ad 100644 Binary files a/TiSideMenu.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/UserInterfaceState.xcuserstate and b/TiSideMenu.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/TiSideMenu.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/WorkspaceSettings.xcsettings b/TiSideMenu.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..bfffcfe --- /dev/null +++ b/TiSideMenu.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + SnapshotAutomaticallyBeforeSignificantChanges + + + diff --git a/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..fe2b454 --- /dev/null +++ b/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,5 @@ + + + diff --git a/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/Build & Test.xcscheme b/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/Build & Test.xcscheme index 823e341..329edac 100644 --- a/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/Build & Test.xcscheme +++ b/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/Build & Test.xcscheme @@ -1,6 +1,6 @@ + + + + diff --git a/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/TiSideMenu.xcscheme b/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/TiSideMenu.xcscheme index 111b994..43aa8b3 100644 --- a/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/TiSideMenu.xcscheme +++ b/TiSideMenu.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/TiSideMenu.xcscheme @@ -1,6 +1,6 @@ + + + + diff --git a/dist/de.marcelpociot.sidemenu-iphone-1.0.zip b/dist/de.marcelpociot.sidemenu-iphone-1.0.zip index c3004e1..485e765 100644 Binary files a/dist/de.marcelpociot.sidemenu-iphone-1.0.zip and b/dist/de.marcelpociot.sidemenu-iphone-1.0.zip differ diff --git a/dist/de.marcelpociot.sidemenu-iphone-1.1.zip b/dist/de.marcelpociot.sidemenu-iphone-1.1.zip new file mode 100644 index 0000000..647fa0e Binary files /dev/null and b/dist/de.marcelpociot.sidemenu-iphone-1.1.zip differ diff --git a/dist/de.marcelpociot.sidemenu-iphone-1.2.1.zip b/dist/de.marcelpociot.sidemenu-iphone-1.2.1.zip new file mode 100644 index 0000000..25db28f Binary files /dev/null and b/dist/de.marcelpociot.sidemenu-iphone-1.2.1.zip differ diff --git a/dist/de.marcelpociot.sidemenu-iphone-1.2.zip b/dist/de.marcelpociot.sidemenu-iphone-1.2.zip new file mode 100644 index 0000000..3975f58 Binary files /dev/null and b/dist/de.marcelpociot.sidemenu-iphone-1.2.zip differ diff --git a/dist/de.marcelpociot.sidemenu-iphone-2.0.zip b/dist/de.marcelpociot.sidemenu-iphone-2.0.zip new file mode 100644 index 0000000..54efc93 Binary files /dev/null and b/dist/de.marcelpociot.sidemenu-iphone-2.0.zip differ diff --git a/dist/de.marcelpociot.sidemenu-iphone-2.1.zip b/dist/de.marcelpociot.sidemenu-iphone-2.1.zip new file mode 100644 index 0000000..a77a498 Binary files /dev/null and b/dist/de.marcelpociot.sidemenu-iphone-2.1.zip differ diff --git a/dist/de.marcelpociot.sidemenu-iphone-2.2.zip b/dist/de.marcelpociot.sidemenu-iphone-2.2.zip new file mode 100644 index 0000000..9e4517c Binary files /dev/null and b/dist/de.marcelpociot.sidemenu-iphone-2.2.zip differ diff --git a/example/app.js b/example/app.js index 7e01621..f15a099 100644 --- a/example/app.js +++ b/example/app.js @@ -1,8 +1,9 @@ var TiSideMenu = require('de.marcelpociot.sidemenu'); -var menuWin = Ti.UI.createWindow({ - backgroundColor:'transparent' +var leftMenuWin = Ti.UI.createWindow({ + backgroundColor:'transparent', + statusBarStyle: Titanium.UI.iPhone.StatusBar.LIGHT_CONTENT }); var leftTableView = Ti.UI.createTableView({ top: 100, @@ -17,7 +18,28 @@ var leftTableView = Ti.UI.createTableView({ {title:'Reset Window',color: 'white'} ] }); -menuWin.add(leftTableView); +leftMenuWin.add(leftTableView); + + +var rightMenuWin = Ti.UI.createWindow({ + backgroundColor:'transparent', + statusBarStyle: Titanium.UI.iPhone.StatusBar.LIGHT_CONTENT +}); +var rightTableView = Ti.UI.createTableView({ + top: 100, + font:{fontSize:12,color: '#ffffff'}, + rowHeight:40, + backgroundColor:'transparent', + data:[ + {title:'Row 1',color: 'white'}, + {title:'Row 2',color: 'white'}, + {title:'Change Center Window',color: 'white'}, + {title:'Push new Window',color: 'white'}, + {title:'Reset Window',color: 'white'} + ] +}); +rightMenuWin.add(rightTableView); + leftTableView.addEventListener("click", function(e){ switch(e.index){ case 0: @@ -29,7 +51,10 @@ leftTableView.addEventListener("click", function(e){ var newWin = Ti.UI.createWindow({ backgroundColor:'red' }); - win.setContentWindow(newWin); + win.setContentWindow({ + window: newWin, + animated: true + }); win.hideMenuViewController(); break; case 3: @@ -49,26 +74,35 @@ leftTableView.addEventListener("click", function(e){ function createContentWindow() { var contentWin = Ti.UI.createWindow({ - backgroundColor:'#ddd', + backgroundColor:'transparent', title:"RE Side Menu", barColor:"#f7f7f7" }); - toggleMenuBtn = Ti.UI.createButton({ - title: 'MENU' + var toggleLeftMenuBtn = Ti.UI.createButton({ + title: 'LEFT' + }); + contentWin.leftNavButton = toggleLeftMenuBtn; + toggleLeftMenuBtn.addEventListener('click',function(e) + { + win.presentLeftMenuViewController(); + }); + + var toggleRightMenuBtn = Ti.UI.createButton({ + title: 'RIGHT' }); - contentWin.leftNavButton = toggleMenuBtn; - toggleMenuBtn.addEventListener('click',function(e) + contentWin.rightNavButton = toggleRightMenuBtn; + toggleRightMenuBtn.addEventListener('click',function(e) { - win.presentMenuViewController(); + win.presentRightMenuViewController(); }); // Module settings - scaleContentViewLabel = Ti.UI.createLabel({ + var scaleContentViewLabel = Ti.UI.createLabel({ text: 'Scale content view:', top: 50, left: 10 - }) - scaleContentViewBtn = Ti.UI.createSwitch({ + }); + var scaleContentViewBtn = Ti.UI.createSwitch({ value: true, top: 50, right: 10 @@ -81,12 +115,12 @@ function createContentWindow() }); - scaleBackgroundImageViewLabel = Ti.UI.createLabel({ + var scaleBackgroundImageViewLabel = Ti.UI.createLabel({ text: 'Scale background image:', top: 100, left: 10 - }) - scaleBackgroundImageViewBtn = Ti.UI.createSwitch({ + }); + var scaleBackgroundImageViewBtn = Ti.UI.createSwitch({ value: true, top: 100, right: 10 @@ -98,16 +132,33 @@ function createContentWindow() win.setScaleBackgroundImageView( scaleBackgroundImageViewBtn.value ); }); - parallaxLabel = Ti.UI.createLabel({ - text: 'Parallax enabled:', + var scaleMenuViewLabel = Ti.UI.createLabel({ + text: 'Scale menu view:', top: 150, left: 10 - }) - parallaxBtn = Ti.UI.createSwitch({ + }); + var scaleMenuViewBtn = Ti.UI.createSwitch({ value: true, top: 150, right: 10 }); + contentWin.add( scaleMenuViewLabel ); + contentWin.add( scaleMenuViewBtn ); + scaleMenuViewBtn.addEventListener('change',function(e) + { + win.setScaleMenuView( scaleMenuViewBtn.value ); + }); + + var parallaxLabel = Ti.UI.createLabel({ + text: 'Parallax enabled:', + top: 200, + left: 10 + }); + var parallaxBtn = Ti.UI.createSwitch({ + value: true, + top: 200, + right: 10 + }); contentWin.add( parallaxLabel ); contentWin.add( parallaxBtn ); parallaxBtn.addEventListener('change',function(e) @@ -116,14 +167,14 @@ function createContentWindow() }); - panLabel = Ti.UI.createLabel({ + var panLabel = Ti.UI.createLabel({ text: 'Pan gesture enabled:', - top: 200, + top: 250, left: 10 }); - panBtn = Ti.UI.createSwitch({ + var panBtn = Ti.UI.createSwitch({ value: true, - top: 200, + top: 250, right: 10 }); contentWin.add( panLabel ); @@ -133,13 +184,13 @@ function createContentWindow() win.setPanGestureEnabled( panBtn.value ); }); - scaleLabel = Ti.UI.createLabel({ + var scaleLabel = Ti.UI.createLabel({ text: 'Content View scale:', - top: 250, + top: 300, left: 10 - }) + }); var scaleSlider = Titanium.UI.createSlider({ - top: 290, + top: 340, min: 0, max: 100, width: '100%', @@ -153,6 +204,7 @@ function createContentWindow() var navController = Ti.UI.iOS.createNavigationWindow({ + statusBarStyle: Titanium.UI.iPhone.StatusBar.LIGHT_CONTENT, window : contentWin }); return navController; @@ -160,30 +212,43 @@ function createContentWindow() var contentWindow = createContentWindow(); var win = TiSideMenu.createSideMenu({ contentView: contentWindow, - menuView: menuWin, - backgroundImage: 'stars.png' + leftMenuView: leftMenuWin, + rightMenuView: rightMenuWin, + backgroundImage: 'stars.png', + contentViewScaleValue: 0.2, + scaleContentView: true, + panGestureEnabled: true, + panFromEdge: true, + scaleBackgroundImageView: true, + scaleMenuView: true, + parallaxEnabled: true, + // Blur options + blurBackground: false, + tintColor: '#ffffff', + blurRadius: 0, + iterations: 0 }); win.addEventListener("willShowMenuViewController",function() { - alert("Will show menu view controller"); + //alert("Will show menu view controller"); }); win.addEventListener("didShowMenuViewController",function() { - alert("Did show menu view controller"); + //alert("Did show menu view controller"); }); win.addEventListener("willHideMenuViewController",function() { - alert("Will hide menu view controller"); + //alert("Will hide menu view controller"); }); win.addEventListener("didHideMenuViewController",function() { - alert("Did hide menu view controller"); + //alert("Did hide menu view controller"); }); -win.open(); \ No newline at end of file +win.open(); diff --git a/manifest b/manifest index 00982e6..2956625 100644 --- a/manifest +++ b/manifest @@ -2,12 +2,12 @@ # this is your module manifest and used by Titanium # during compilation, packaging, distribution, etc. # -version: 1.0 -apiversion: 2 +version: 2.2 +apiversion: 3 description: My module -author: Your Name -license: Specify your license -copyright: Copyright (c) 2013 by Your Company +author: Marcel Pociot +license: MIT +copyright: Copyright (c) 2013-2014 by Marcel Pociot # these should not be edited @@ -15,4 +15,5 @@ name: TiSideMenu moduleid: de.marcelpociot.sidemenu guid: 544290ca-7102-4cf4-8b20-feedb53f2045 platform: iphone -minsdk: 3.1.3.GA +minsdk: 3.4.0.GA +architectures: armv7 arm64 i386 x86_64 diff --git a/module.xcconfig b/module.xcconfig index 80ca884..329ce3c 100644 --- a/module.xcconfig +++ b/module.xcconfig @@ -1,27 +1 @@ -// -// PLACE ANY BUILD DEFINITIONS IN THIS FILE AND THEY WILL BE -// PICKED UP DURING THE APP BUILD FOR YOUR MODULE -// -// see the following webpage for instructions on the settings -// for this file: -// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/XcodeBuildSystem/400-Build_Configurations/build_configs.html -// - -// -// How to add a Framework (example) -// -// OTHER_LDFLAGS=$(inherited) -framework Foo -// -// Adding a framework for a specific version(s) of iPhone: -// -// OTHER_LDFLAGS[sdk=iphoneos4*]=$(inherited) -framework Foo -// OTHER_LDFLAGS[sdk=iphonesimulator4*]=$(inherited) -framework Foo -// -// -// How to add a compiler define: -// -// OTHER_CFLAGS=$(inherited) -DFOO=1 -// -// -// IMPORTANT NOTE: always use $(inherited) in your overrides -// +OTHER_LDFLAGS=$(inherited) -framework QuartzCore -framework Accelerate -framework CoreImage \ No newline at end of file diff --git a/titanium.xcconfig b/titanium.xcconfig index 9b519ba..086b844 100644 --- a/titanium.xcconfig +++ b/titanium.xcconfig @@ -4,13 +4,13 @@ // OF YOUR TITANIUM SDK YOU'RE BUILDING FOR // // -TITANIUM_SDK_VERSION = 3.1.3.GA +TITANIUM_SDK_VERSION = 3.4.0.GA // // THESE SHOULD BE OK GENERALLY AS-IS // -TITANIUM_SDK = /Users/marcelpociot/Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) +TITANIUM_SDK = $HOME/Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) TITANIUM_BASE_SDK = "$(TITANIUM_SDK)/iphone/include" TITANIUM_BASE_SDK2 = "$(TITANIUM_SDK)/iphone/include/TiCore" HEADER_SEARCH_PATHS= $(TITANIUM_BASE_SDK) $(TITANIUM_BASE_SDK2)