├── VERSION ├── Demos ├── Basic │ ├── BasicDemo │ │ ├── en.lproj │ │ │ └── InfoPlist.strings │ │ ├── Default.png │ │ ├── Default@2x.png │ │ ├── Default-568h@2x.png │ │ ├── View Controllers │ │ │ ├── MenuViewController.h │ │ │ ├── DetailsViewController.h │ │ │ ├── MenuViewController.m │ │ │ ├── DetailsViewController.m │ │ │ └── DetailsViewController.xib │ │ ├── AppDelegate.h │ │ ├── BasicDemo-Prefix.pch │ │ ├── main.m │ │ ├── BasicDemo-Info.plist │ │ └── AppDelegate.m │ └── BasicDemo.xcodeproj │ │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── BasicDemo.xccheckout │ │ └── project.pbxproj └── Demos.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── Demos.xccheckout ├── NVSlideMenuController.podspec ├── .gitignore ├── LICENSE.md ├── README.md ├── CHANGELOG.md └── lib └── NVSlideMenuController ├── NVSlideMenuController.h └── NVSlideMenuController.m /VERSION: -------------------------------------------------------------------------------- 1 | 1.5.8 -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nverinaud/NVSlideMenuController/HEAD/Demos/Basic/BasicDemo/Default.png -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nverinaud/NVSlideMenuController/HEAD/Demos/Basic/BasicDemo/Default@2x.png -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nverinaud/NVSlideMenuController/HEAD/Demos/Basic/BasicDemo/Default-568h@2x.png -------------------------------------------------------------------------------- /Demos/Demos.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/View Controllers/MenuViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MenuViewController.h 3 | // BasicDemo 4 | // 5 | // Created by Nicolas Verinaud on 31/12/12. 6 | // Copyright (c) 2012 Nicolas Verinaud. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MenuViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // BasicDemo 4 | // 5 | // Created by Nicolas Verinaud on 31/12/12. 6 | // Copyright (c) 2012 Nicolas Verinaud. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/BasicDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'BasicDemo' target in the 'BasicDemo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iOS SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // BasicDemo 4 | // 5 | // Created by Nicolas Verinaud on 02/01/13. 6 | // Copyright (c) 2013 Nicolas VERINAUD. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/View Controllers/DetailsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DetailsViewController.h 3 | // BasicDemo 4 | // 5 | // Created by Nicolas Verinaud on 31/12/12. 6 | // Copyright (c) 2012 Nicolas Verinaud. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DetailsViewController : UIViewController 12 | 13 | @property (nonatomic, strong) id detailedObject; 14 | 15 | @property (nonatomic, copy) void(^onShowMenuButtonClicked)(void); 16 | - (void)setOnShowMenuButtonClicked:(void (^)(void))onShowMenuButtonClicked; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /NVSlideMenuController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "NVSlideMenuController" 3 | s.version = "1.5.8" 4 | s.summary = "A slide menu done right for iOS." 5 | s.homepage = "https://github.com/nverinaud/NVSlideMenuController" 6 | s.license = 'MIT' 7 | s.author = { "Nicolas VERINAUD" => "n.verinaud@gmail.com" } 8 | s.source = { :git => "https://github.com/nverinaud/NVSlideMenuController.git", :tag => "v1.5.8" } 9 | s.platform = :ios, '5.0' 10 | s.source_files = 'lib', 'lib/**/*.{h,m}' 11 | s.framework = 'QuartzCore' 12 | s.requires_arc = false 13 | end 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ########## 2 | # Xcode 3 | ########## 4 | build/* 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | 17 | ########## 18 | # Python 19 | ########## 20 | *.py[co] 21 | 22 | # Packages 23 | *.egg 24 | *.egg-info 25 | dist 26 | build 27 | eggs 28 | parts 29 | bin 30 | var 31 | sdist 32 | develop-eggs 33 | .installed.cfg 34 | 35 | # Installer logs 36 | pip-log.txt 37 | 38 | # Unit test / coverage reports 39 | .coverage 40 | .tox 41 | 42 | #Translations 43 | *.mo 44 | 45 | #Mr Developer 46 | .mr.developer.cfg 47 | 48 | ########## 49 | # OS X 50 | ########## 51 | .DS_Store 52 | Icon? 53 | 54 | # Thumbnails 55 | ._* 56 | 57 | # Files that might appear on external disk 58 | .Spotlight-V100 59 | .Trashes 60 | 61 | ########## 62 | # vim 63 | ########## 64 | .*.sw[a-z] 65 | *.un~ 66 | Session.vim 67 | 68 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2013 Nicolas VERINAUD 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/BasicDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Demos/Demos.xcworkspace/xcshareddata/Demos.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 29214239-5D7E-448E-894A-BBD9A8C10C38 9 | IDESourceControlProjectName 10 | Demos 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | D4F56436-C0D4-47CE-87FC-332709354658 14 | ssh://github.com/nverinaud/NVSlideMenuController.git 15 | 16 | IDESourceControlProjectPath 17 | Demos/Demos.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | D4F56436-C0D4-47CE-87FC-332709354658 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | ssh://github.com/nverinaud/NVSlideMenuController.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | D4F56436-C0D4-47CE-87FC-332709354658 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | D4F56436-C0D4-47CE-87FC-332709354658 36 | IDESourceControlWCCName 37 | NVSlideMenuController 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo.xcodeproj/project.xcworkspace/xcshareddata/BasicDemo.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 34F85F4D-AD26-4514-947C-0FF3FE220181 9 | IDESourceControlProjectName 10 | BasicDemo 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 58C815CD-FAFD-482E-B11F-4C9EAFF3E6F8 14 | ssh://github.com/nverinaud/NVSlideMenuController.git 15 | 16 | IDESourceControlProjectPath 17 | Demos/Basic/BasicDemo.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 58C815CD-FAFD-482E-B11F-4C9EAFF3E6F8 21 | ../../../.. 22 | 23 | IDESourceControlProjectURL 24 | ssh://github.com/nverinaud/NVSlideMenuController.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 58C815CD-FAFD-482E-B11F-4C9EAFF3E6F8 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 58C815CD-FAFD-482E-B11F-4C9EAFF3E6F8 36 | IDESourceControlWCCName 37 | NVSlideMenuController 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // BasicDemo 4 | // 5 | // Created by Nicolas Verinaud on 31/12/12. 6 | // Copyright (c) 2012 Nicolas Verinaud. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "NVSlideMenuController.h" 11 | #import "MenuViewController.h" 12 | #import "DetailsViewController.h" 13 | 14 | void uncaughtExceptionHandler(NSException*); 15 | 16 | @implementation AppDelegate 17 | 18 | #if !__has_feature(objc_arc) 19 | - (void)dealloc 20 | { 21 | [_window release]; 22 | 23 | [super dealloc]; 24 | } 25 | #endif 26 | 27 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 28 | { 29 | NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); 30 | 31 | #if !__has_feature(objc_arc) 32 | self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; 33 | #else 34 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 35 | #endif 36 | 37 | MenuViewController *menuVC = [[MenuViewController alloc] initWithStyle:UITableViewStyleGrouped]; 38 | UINavigationController *menuNavigationController = [[UINavigationController alloc] initWithRootViewController:menuVC]; 39 | 40 | DetailsViewController *detailsVC = [[DetailsViewController alloc] init]; 41 | detailsVC.detailedObject = @"Welcome Slide Menu !"; 42 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:detailsVC]; 43 | 44 | NVSlideMenuController *slideMenuVC = [[NVSlideMenuController alloc] initWithMenuViewController:menuNavigationController andContentViewController:navController]; 45 | 46 | self.window.rootViewController = slideMenuVC; 47 | 48 | #if !__has_feature(objc_arc) 49 | [menuVC release]; 50 | [detailsVC release]; 51 | [menuNavigationController release]; 52 | [navController release]; 53 | [slideMenuVC release]; 54 | #endif 55 | 56 | self.window.backgroundColor = [UIColor whiteColor]; 57 | [self.window makeKeyAndVisible]; 58 | return YES; 59 | } 60 | 61 | @end 62 | 63 | void uncaughtExceptionHandler(NSException *exception) 64 | { 65 | NSLog(@"CRASH: %@", exception); 66 | NSLog(@"Stack Trace: %@", [exception callStackSymbols]); 67 | } 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NVSlideMenuController 2 | 3 | A slide menu done right. 4 | 5 | ## Requirements 6 | 7 | * You can use ARC or not, this library supports both 8 | * iOS 5.0+ 9 | 10 | ## Usage 11 | 12 | * Drop `lib/NVSlideMenuController/NVSlideMenuController.{h|m}` in your project 13 | * Add `QuartzCore.framework` 14 | 15 | **Create a slide menu** 16 | 17 | ```objective-c 18 | UIViewController *menuViewController = ... ; // Your menu view controller 19 | UIViewController *contentViewController = ... ; // The initial content view controller (home page ?) 20 | 21 | NVSlideMenuController *slideMenuController = [[NVSlideMenuController alloc] initWithMenuViewController:menuViewController andContentViewController:contentViewController]; 22 | 23 | self.window.rootViewController = slideMenuController; // Assuming you are in app delegate did finish launching 24 | ``` 25 | 26 | **Change & show new content from the menu** 27 | 28 | ```objective-c 29 | // Inside your menuViewController 30 | UIViewController *newContentViewController = ... ; // Create & configure your new content view controller (as usual) 31 | [self.slideMenuController closeMenuBehindContentViewController:newContentViewController animated:YES completion:nil]; 32 | ``` 33 | 34 | **NVSlideMenuController callbacks** 35 | 36 | The library provides 4 methods through a UIViewController category. 37 | You can override them to manage the slide in/out of the content view controller. It is best described by the provided demo app. 38 | 39 | ```objective-c 40 | @interface UIViewController (NVSlideMenuControllerCallbacks) 41 | 42 | - (void)viewWillSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController; 43 | - (void)viewDidSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController; 44 | - (void)viewWillSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController; 45 | - (void)viewDidSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController; 46 | 47 | @end 48 | ``` 49 | 50 | **Change the slide direction** 51 | 52 | You can specify the slide direction by setting the `slideDirection` property to `NVSlideMenuControllerSlideFromLeftToRight` 53 | or `NVSlideMenuControllerSlideFromRightToLeft`. The views will update accordingly if needed (look at the demo app for a taste). 54 | You can also animate the change. 55 | 56 | ```objective-c 57 | // Inside your view controller (menu or content) 58 | [self.slideMenuController setSlideDirection:NVSlideMenuControllerSlideFromRightToLeft animated:YES]; 59 | // or more simply... 60 | self.slideMenuController.slideDirection = NVSlideMenuControllerSlideFromRightToLeft; // this one will not animate 61 | ``` 62 | 63 | **Enable/Disable the pan gesture** 64 | 65 | You could need to disable the pan gesture, for example when your content view controller has a table view with reorder control (see issue [#2](https://github.com/nverinaud/NVSlideMenuController/issues/2)). 66 | 67 | ```objective-c 68 | // For example when your view controller enter in editing mode 69 | - (void)setEditing:(BOOL)editing animated:(BOOL)animated 70 | { 71 | [super setEditing:editing animated:animated]; 72 | 73 | if (editing) 74 | self.slideMenuController.panGestureEnabled = NO; 75 | } 76 | ``` 77 | 78 | For more have a look at the demo app `;-]` 79 | 80 | ## Author 81 | 82 | Nicolas VERINAUD ([@nverinaud](https://twitter.com/nverinaud)) 83 | 84 | ## License 85 | 86 | Released under the MIT License. For more see `LICENSE.md`. 87 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Release 1.5.7 4 | 5 | * FIX: issue [#33](https://github.com/nverinaud/NVSlideMenuController/issues/33) has been fixed. Closing the menu while the menu view controller's view is not loaded does not cause it to load in an inconsistent manner. 6 | 7 | ## Release 1.5.6 8 | 9 | * FIX: forward status bar style & appearance to child view controllers. 10 | 11 | ## Release 1.5.5 12 | 13 | * FIX: fix the toggle of the content view. 14 | 15 | ## Release 1.5.4 16 | 17 | * FIX: fix implementation of custom container view controller. (Thanks to [Gabriel Reis](https://github.com/greis)) 18 | 19 | ## Release 1.5.3 20 | 21 | * FIX: rotation issue introduced in 1.5.2 (sorry about that!) 22 | * FIX: rotation issue on panning (issue #8) 23 | 24 | ## Release 1.5.2 25 | 26 | * NEW: You can now enable/disable the shadow on the content view. (Thanks to [Gabriel Reis & Matt Polito from Hashrocket](https://github.com/hashrocketeer)) 27 | * NEW: add `menuWidth` property, it replaces `contentViewWidthWhenMenuIsOpen` 28 | * DEPRECATION: `contentViewWidthWhenMenuIsOpen` is now deprecated 29 | 30 | ## Release 1.5.1 31 | 32 | * FIX: fix initial bounds of content view controller in viewDidLoad. 33 | 34 | ## Release 1.5.0 35 | 36 | * ENHANCEMENT: Remove the panGesture's requirement that the tapGesture fails. (Thanks to [David Berry](https://github.com/DavidBarry)) 37 | * NEW: You can now make the content view bounce when navigating. (Thanks to [David Berry](https://github.com/DavidBarry)) 38 | 39 | ## Release 1.4.3 40 | 41 | * FIX: issue [#5](https://github.com/nverinaud/NVSlideMenuController/issues/5) has been fixed. 42 | 43 | ## Release 1.4.2 44 | 45 | * FIX: fix bridge cast warning when not using ARC. 46 | 47 | ## Release 1.4.1 48 | 49 | * FIX: fix performance issue due to the shadow. 50 | 51 | ## Release 1.4.0 52 | 53 | * NEW: You can now completly hide the content view and show it partially. 54 | * DEPRECATED APIs: 55 | * `-setContentViewController:animated:completion:` replaced by `-closeMenuBehindContentViewController:animated:completion:` 56 | * `-showContentViewControllerAnimated:completion:` replaced by `-closeMenuAnimated:completion:` 57 | * `-showMenuAnimated:completion:` replaced by `-openMenuAnimated:completion:`. 58 | 59 | ## Release 1.3.2 60 | 61 | * NEW: add `contentViewWidthWhenMenuIsOpen` property. 62 | 63 | ## Release 1.3.1 64 | 65 | * IMPORTANT FIX: the pan gesture now works fine. 66 | * NEW: ARC is supported conditionaly. 67 | 68 | ## Release 1.3.0 69 | 70 | * NEW: You can now change the slide direction (left -> right or right -> left). 71 | 72 | ## Release 1.2.0 73 | 74 | * NEW: add `NVSlideMenuControllerCallbacks` category on `UIViewController`. 75 | * NEW: default implementation of `NVSlideMenuControllerCallbacks` category has 76 | been added to View Controller Containers provided by Apple. 77 | 78 | ## Release 1.1.3 79 | 80 | * NEW: add `panGestureEnabled` property. 81 | * DEPRECATED: `panEnabledWhenSlideMenuIsHidden` property is now deprecated. 82 | * FIX: issue [#2](https://github.com/nverinaud/NVSlideMenuController/issues/2) has been fixed. 83 | 84 | ## Release 1.1.2 85 | 86 | * UPDATE: make `-[NVSlideMenuController isMenuOpen]` a public API. 87 | 88 | ## Release 1.1.1 89 | 90 | * FIX: fix a typo in README for `no ARC compiler flag`. 91 | 92 | ## Release 1.0.2 93 | 94 | * NEW: add a nice shadow on the content view controller's view. 95 | 96 | ## Release 1.0.1 97 | 98 | * FIX: The menu state is now preserved when presenting a view controller modally. 99 | 100 | ## Release 1.0.0 101 | 102 | * First release. 103 | -------------------------------------------------------------------------------- /lib/NVSlideMenuController/NVSlideMenuController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NVSlideMenuViewController.h 3 | // NVSlideMenuViewController 4 | // 5 | // Created by Nicolas Verinaud on 31/12/12. 6 | // Copyright (c) 2012 Nicolas Verinaud. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, NVSlideMenuControllerSlideDirection) 12 | { 13 | NVSlideMenuControllerSlideFromLeftToRight = 0, // default, slide from left to right to open the menu 14 | NVSlideMenuControllerSlideFromRightToLeft // slide from right to left to open the menu 15 | }; 16 | 17 | 18 | @interface NVSlideMenuController : UIViewController 19 | 20 | @property (nonatomic, readonly, strong) UIViewController *menuViewController; 21 | @property (nonatomic, readonly, strong) UIViewController *contentViewController; 22 | @property (nonatomic, assign) BOOL panGestureEnabled; // default is YES. Set it to NO to disable the pan gesture 23 | @property (nonatomic, assign) CGFloat menuWidth; // default is 276 24 | @property (nonatomic, assign) BOOL autoAdjustMenuWidth; // default is YES. Set it to NO to keep the menu the same width as the SlideMenuController's view 25 | @property (nonatomic, assign) BOOL bounceWhenNavigating; // default is NO. Determines whether the contentViewController will bounce offscreen when calling 26 | // `-closeMenuBehindContentViewController:animated:completion:` 27 | @property (nonatomic, assign) BOOL showShadowOnContentView; // default is YES. Set it to NO to remove shadow from content view 28 | 29 | - (id)initWithMenuViewController:(UIViewController *)menuViewController andContentViewController:(UIViewController *)contentViewController; 30 | 31 | /** @name Navigation */ 32 | - (IBAction)toggleMenuAnimated:(id)sender; // Convenience for use with target/action, always animate 33 | 34 | - (void)openMenuAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion; 35 | - (void)closeMenuAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion; 36 | - (void)closeMenuBehindContentViewController:(UIViewController *)contentViewController animated:(BOOL)animated completion:(void(^)(BOOL finished))completion; 37 | - (void)closeMenuBehindContentViewController:(UIViewController *)contentViewController animated:(BOOL)animated bounce:(BOOL)bounce completion:(void(^)(BOOL finished))completion; 38 | 39 | - (void)hideContentViewControllerAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion; // hide the content view controller, the menu view controller will be resized 40 | - (void)partiallyShowContentViewControllerAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion; // show a part (equal to contentViewWidthWhenMenuIsOpen) of the content view controller, the menu view controller will be resized 41 | 42 | /** @name Slide direction */ 43 | @property (nonatomic, assign) NVSlideMenuControllerSlideDirection slideDirection; 44 | - (void)setSlideDirection:(NVSlideMenuControllerSlideDirection)slideDirection animated:(BOOL)animated; 45 | 46 | /** @name Menu state information */ 47 | - (BOOL)isMenuOpen; 48 | - (BOOL)isContentViewHidden; 49 | 50 | @end 51 | 52 | 53 | #pragma mark - UIViewController (NVSlideMenuController) 54 | 55 | @interface UIViewController (NVSlideMenuController) 56 | 57 | @property (nonatomic, readonly) NVSlideMenuController *slideMenuController; 58 | 59 | @end 60 | 61 | 62 | #pragma mark - UIViewController (NVSlideMenuControllerCallbacks) 63 | 64 | /** 65 | Subclasses may override these methods to perform custom actions (such as disable interaction with a web view or a table view) 66 | when they slide in our out. 67 | These callbacks are only called on the contentViewController of the slideMenuController. 68 | */ 69 | @interface UIViewController (NVSlideMenuControllerCallbacks) 70 | 71 | - (void)viewWillSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController; // default implementation does nothing 72 | - (void)viewDidSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController; // default implementation does nothing 73 | - (void)viewWillSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController; // default implementation does nothing 74 | - (void)viewDidSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController; // default implementation does nothing 75 | 76 | @end 77 | 78 | 79 | #pragma mark - NVSlideMenuController (Deprecated) 80 | 81 | @interface NVSlideMenuController (Deprecated) 82 | 83 | @property (nonatomic, assign) CGFloat contentViewWidthWhenMenuIsOpen DEPRECATED_ATTRIBUTE; // default is 44.0, DEPRECATED use `menuWidth` property instead 84 | 85 | - (void)setContentViewController:(UIViewController *)contentViewController animated:(BOOL)animated completion:(void(^)(BOOL finished))completion DEPRECATED_ATTRIBUTE; // Use `-closeMenuBehindContentViewController:animated:completion:` instead 86 | - (void)showContentViewControllerAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion DEPRECATED_ATTRIBUTE; // Use `-closeMenuAnimated:completion:` instead 87 | - (void)showMenuAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion DEPRECATED_ATTRIBUTE; // Use `-openMenuAnimated:completion:` instead 88 | 89 | @property (nonatomic, assign) BOOL panEnabledWhenSlideMenuIsHidden DEPRECATED_ATTRIBUTE; // Use `panGestureEnabled` property to control whether the pan gesture is enabled. 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/View Controllers/MenuViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MenuViewController.m 3 | // BasicDemo 4 | // 5 | // Created by Nicolas Verinaud on 31/12/12. 6 | // Copyright (c) 2012 Nicolas Verinaud. All rights reserved. 7 | // 8 | 9 | #import "MenuViewController.h" 10 | #import "DetailsViewController.h" 11 | #import "NVSlideMenuController.h" 12 | 13 | #define NUMBER_OF_SECTIONS 3 14 | #define NUMBER_OF_ROWS 10 15 | 16 | @interface MenuViewController () 17 | 18 | - (void)togglePanGestureEnabled:(UIBarButtonItem *)sender; 19 | - (void)toggleSlideDirection:(UIBarButtonItem *)sender; 20 | 21 | @end 22 | 23 | 24 | 25 | @implementation MenuViewController 26 | 27 | - (id)initWithStyle:(UITableViewStyle)style 28 | { 29 | self = [super initWithStyle:style]; 30 | return self; 31 | } 32 | 33 | 34 | #pragma mark - View lifecycle 35 | 36 | - (void)viewDidLoad 37 | { 38 | [super viewDidLoad]; 39 | 40 | self.clearsSelectionOnViewWillAppear = NO; 41 | self.title = NSLocalizedString(@"Menu", nil); 42 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Pan Enabled", nil) 43 | style:UIBarButtonItemStyleBordered 44 | target:self 45 | action:@selector(togglePanGestureEnabled:)]; 46 | 47 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"L->R", nil) 48 | style:UIBarButtonItemStyleBordered 49 | target:self 50 | action:@selector(toggleSlideDirection:)]; 51 | 52 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 53 | } 54 | 55 | 56 | - (void)viewWillAppear:(BOOL)animated 57 | { 58 | [super viewWillAppear:animated]; 59 | 60 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 61 | } 62 | 63 | 64 | - (void)viewDidAppear:(BOOL)animated 65 | { 66 | [super viewDidAppear:animated]; 67 | 68 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 69 | 70 | [self.tableView scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionNone animated:animated]; 71 | } 72 | 73 | 74 | - (void)viewWillDisappear:(BOOL)animated 75 | { 76 | [super viewWillDisappear:animated]; 77 | 78 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 79 | } 80 | 81 | 82 | - (void)viewDidDisappear:(BOOL)animated 83 | { 84 | [super viewDidDisappear:animated]; 85 | 86 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 87 | } 88 | 89 | #pragma mark - Table view data source 90 | 91 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 92 | { 93 | return NUMBER_OF_SECTIONS; 94 | } 95 | 96 | 97 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 98 | { 99 | return NUMBER_OF_ROWS; 100 | } 101 | 102 | 103 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 104 | { 105 | static NSString *CellIdentifier = @"Cell"; 106 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 107 | if (!cell) 108 | { 109 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 110 | #if !__has_feature(objc_arc) 111 | [cell autorelease]; 112 | #endif 113 | } 114 | 115 | // First row of first section toggle menu full screen 116 | if (indexPath.section == 0 && indexPath.row == 0) 117 | cell.textLabel.text = NSLocalizedString(@"Toggle Content View", nil); 118 | // Second row of first section shows a modal view controller 119 | else if (indexPath.section == 0 && indexPath.row == 1) 120 | cell.textLabel.text = NSLocalizedString(@"Show modal", nil); 121 | else 122 | cell.textLabel.text = [NSString stringWithFormat:@"Section: %ld - Row: %ld", (long)indexPath.section, (long)indexPath.row]; 123 | 124 | return cell; 125 | } 126 | 127 | 128 | #pragma mark - Table view delegate 129 | 130 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 131 | { 132 | if (self.slideMenuController) 133 | { 134 | DetailsViewController *detailsVC = [DetailsViewController new]; 135 | detailsVC.detailedObject = indexPath; 136 | 137 | if (indexPath.section == 0 && indexPath.row == 0) 138 | { 139 | if ([self.slideMenuController isContentViewHidden]) 140 | [self.slideMenuController partiallyShowContentViewControllerAnimated:YES completion:nil]; 141 | else 142 | [self.slideMenuController hideContentViewControllerAnimated:YES completion:nil]; 143 | 144 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 145 | } 146 | else if (indexPath.section == 0 && indexPath.row == 1) 147 | { 148 | [detailsVC setOnShowMenuButtonClicked:^{ 149 | [self dismissViewControllerAnimated:YES completion:nil]; 150 | }]; 151 | [self presentViewController:detailsVC animated:YES completion:nil]; 152 | } 153 | else 154 | { 155 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:detailsVC]; 156 | [self.slideMenuController closeMenuBehindContentViewController:navController animated:YES completion:nil]; 157 | #if !__has_feature(objc_arc) 158 | [navController release]; 159 | #endif 160 | } 161 | 162 | #if !__has_feature(objc_arc) 163 | [detailsVC release]; 164 | #endif 165 | } 166 | else 167 | { 168 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 169 | } 170 | } 171 | 172 | 173 | #pragma mark - Rotation 174 | 175 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 176 | { 177 | return toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown; 178 | } 179 | 180 | 181 | #pragma mark - Toggle pan gesture enabled 182 | 183 | - (void)togglePanGestureEnabled:(UIBarButtonItem *)sender 184 | { 185 | self.slideMenuController.panGestureEnabled = !self.slideMenuController.panGestureEnabled; 186 | sender.title = self.slideMenuController.panGestureEnabled ? NSLocalizedString(@"Pan Enabled", nil) : NSLocalizedString(@"Pan Disabled", nil); 187 | } 188 | 189 | 190 | #pragma mark - Toggle slide direction 191 | 192 | - (void)toggleSlideDirection:(UIBarButtonItem *)sender 193 | { 194 | if (self.slideMenuController.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 195 | { 196 | [self.slideMenuController setSlideDirection:NVSlideMenuControllerSlideFromRightToLeft animated:YES]; 197 | sender.title = NSLocalizedString(@"R->L", nil); 198 | } 199 | else if (self.slideMenuController.slideDirection == NVSlideMenuControllerSlideFromRightToLeft) 200 | { 201 | [self.slideMenuController setSlideDirection:NVSlideMenuControllerSlideFromLeftToRight animated:YES]; 202 | sender.title = NSLocalizedString(@"L->R", nil); 203 | } 204 | } 205 | 206 | 207 | @end 208 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/View Controllers/DetailsViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DetailsViewController.m 3 | // BasicDemo 4 | // 5 | // Created by Nicolas Verinaud on 31/12/12. 6 | // Copyright (c) 2012 Nicolas Verinaud. All rights reserved. 7 | // 8 | 9 | #import "DetailsViewController.h" 10 | #import "NVSlideMenuController.h" 11 | 12 | @interface DetailsViewController () 13 | 14 | @property (strong, nonatomic) IBOutlet UITextView *textView; 15 | @property (strong, nonatomic) IBOutlet UISwitch *bounceSwitch; 16 | @property (strong, nonatomic) IBOutlet UISwitch *menuWidthSwitch; 17 | @property (strong, nonatomic) IBOutlet UIToolbar *toolbar; 18 | - (void)updateTextViewAccordingToSlideMenuControllerDirection; 19 | 20 | // Lazy buttons 21 | @property (strong, nonatomic) UIBarButtonItem *leftBarButtonItem; 22 | @property (strong, nonatomic) UIBarButtonItem *rightBarButtonItem; 23 | - (void)updateBarButtonsAccordingToSlideMenuControllerDirectionAnimated:(BOOL)animated; 24 | 25 | // Actions 26 | - (IBAction)showMenu:(id)sender; 27 | - (IBAction)changeSlideDirection:(id)sender; 28 | - (IBAction)bounceSwitchValueChanged:(id)sender; 29 | - (IBAction)menuWidthSwitchValueChanged:(id)sender; 30 | - (IBAction)hideKeyboard:(id)sender; 31 | 32 | @end 33 | 34 | @implementation DetailsViewController 35 | 36 | #if !__has_feature(objc_arc) 37 | - (void)dealloc 38 | { 39 | NSLog(@"%p dealloc'ed", self); 40 | 41 | [_detailedObject release]; 42 | [_onShowMenuButtonClicked release]; 43 | 44 | [_textView release]; 45 | [_bounceSwitch release]; 46 | [_menuWidthSwitch release]; 47 | [_toolbar release]; 48 | 49 | [_leftBarButtonItem release]; 50 | [_rightBarButtonItem release]; 51 | 52 | [super dealloc]; 53 | } 54 | #endif 55 | 56 | 57 | #pragma mark - Creation 58 | #pragma mark - Overriden Designated Initializer 59 | 60 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 61 | { 62 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 63 | if (self) 64 | { 65 | if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) 66 | { 67 | self.edgesForExtendedLayout = UIRectEdgeNone; 68 | } 69 | } 70 | 71 | return self; 72 | } 73 | 74 | 75 | #pragma mark - Memory Management 76 | 77 | - (void)didReceiveMemoryWarning 78 | { 79 | [super didReceiveMemoryWarning]; 80 | 81 | if (![self isViewLoaded]) 82 | { 83 | self.textView = nil; 84 | self.toolbar = nil; 85 | } 86 | } 87 | 88 | 89 | - (void)viewDidUnload 90 | { 91 | [self setTextView:nil]; 92 | [self setBounceSwitch:nil]; 93 | [self setMenuWidthSwitch:nil]; 94 | self.toolbar = nil; 95 | [super viewDidUnload]; 96 | } 97 | 98 | 99 | #pragma mark - View lifecycle 100 | 101 | - (void)viewDidLoad 102 | { 103 | [super viewDidLoad]; 104 | 105 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 106 | 107 | self.title = NSLocalizedString(@"Details", nil); 108 | 109 | [self updateTextViewAccordingToSlideMenuControllerDirection]; 110 | [self updateBarButtonsAccordingToSlideMenuControllerDirectionAnimated:NO]; 111 | 112 | self.bounceSwitch.on = self.slideMenuController.bounceWhenNavigating; 113 | self.menuWidthSwitch.on = self.slideMenuController.autoAdjustMenuWidth; 114 | self.textView.inputAccessoryView = self.toolbar; 115 | } 116 | 117 | 118 | - (void)updateTextViewAccordingToSlideMenuControllerDirection 119 | { 120 | NSString *slideDirectionAsString = nil; 121 | if (self.slideMenuController.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 122 | slideDirectionAsString = @"From left to right"; 123 | else if (self.slideMenuController.slideDirection == NVSlideMenuControllerSlideFromRightToLeft) 124 | slideDirectionAsString = @"From right to left"; 125 | 126 | self.textView.text = [NSString stringWithFormat:@"Direction: %@", slideDirectionAsString]; 127 | } 128 | 129 | 130 | - (void)viewWillAppear:(BOOL)animated 131 | { 132 | [super viewWillAppear:animated]; 133 | 134 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 135 | } 136 | 137 | 138 | - (void)viewDidAppear:(BOOL)animated 139 | { 140 | [super viewDidAppear:animated]; 141 | 142 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 143 | } 144 | 145 | 146 | - (void)viewWillDisappear:(BOOL)animated 147 | { 148 | [super viewWillDisappear:animated]; 149 | 150 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 151 | } 152 | 153 | 154 | - (void)viewDidDisappear:(BOOL)animated 155 | { 156 | [super viewDidDisappear:animated]; 157 | 158 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 159 | } 160 | 161 | 162 | #pragma mark - Slide callbacks 163 | 164 | /** 165 | Here is an example of how you can best use these callbacks ! 166 | */ 167 | - (void)viewWillSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 168 | { 169 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 170 | 171 | [self.textView setEditable:YES]; 172 | [self.textView setScrollEnabled:YES]; 173 | } 174 | 175 | 176 | - (void)viewDidSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 177 | { 178 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 179 | 180 | [self.textView becomeFirstResponder]; 181 | } 182 | 183 | 184 | - (void)viewWillSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 185 | { 186 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 187 | 188 | [self.textView resignFirstResponder]; 189 | } 190 | 191 | 192 | - (void)viewDidSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 193 | { 194 | NSLog(@"%@ - %@ - View Frame: %@", self, NSStringFromSelector(_cmd), NSStringFromCGRect(self.view.frame)); 195 | 196 | [self.textView setEditable:NO]; 197 | [self.textView setScrollEnabled:NO]; 198 | } 199 | 200 | 201 | #pragma mark - Show menu 202 | 203 | - (IBAction)showMenu:(id)sender 204 | { 205 | if (self.onShowMenuButtonClicked) 206 | self.onShowMenuButtonClicked(); 207 | else 208 | [self.slideMenuController openMenuAnimated:YES completion:nil]; 209 | } 210 | 211 | 212 | #pragma mark - Change slide direction 213 | 214 | - (IBAction)changeSlideDirection:(id)sender 215 | { 216 | if (self.slideMenuController.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 217 | self.slideMenuController.slideDirection = NVSlideMenuControllerSlideFromRightToLeft; 218 | else if (self.slideMenuController.slideDirection == NVSlideMenuControllerSlideFromRightToLeft) 219 | self.slideMenuController.slideDirection = NVSlideMenuControllerSlideFromLeftToRight; 220 | 221 | [self updateBarButtonsAccordingToSlideMenuControllerDirectionAnimated:YES]; 222 | [self updateTextViewAccordingToSlideMenuControllerDirection]; 223 | } 224 | 225 | 226 | - (IBAction)bounceSwitchValueChanged:(id)sender 227 | { 228 | UISwitch *theSwitch = sender; 229 | self.slideMenuController.bounceWhenNavigating = theSwitch.isOn; 230 | } 231 | 232 | 233 | - (IBAction)menuWidthSwitchValueChanged:(id)sender 234 | { 235 | UISwitch *theSwitch = sender; 236 | self.slideMenuController.autoAdjustMenuWidth = theSwitch.isOn; 237 | } 238 | 239 | 240 | - (IBAction)hideKeyboard:(id)sender 241 | { 242 | [self.view endEditing:YES]; 243 | } 244 | 245 | 246 | #pragma mark - Lazy buttons 247 | 248 | - (UIBarButtonItem *)leftBarButtonItem 249 | { 250 | if (!_leftBarButtonItem) 251 | { 252 | _leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFastForward 253 | target:self.slideMenuController 254 | action:@selector(toggleMenuAnimated:)]; 255 | } 256 | return _leftBarButtonItem; 257 | } 258 | 259 | 260 | - (UIBarButtonItem *)rightBarButtonItem 261 | { 262 | if (!_rightBarButtonItem) 263 | { 264 | _rightBarButtonItem =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRewind 265 | target:self.slideMenuController 266 | action:@selector(toggleMenuAnimated:)]; 267 | } 268 | 269 | return _rightBarButtonItem; 270 | } 271 | 272 | 273 | - (void)updateBarButtonsAccordingToSlideMenuControllerDirectionAnimated:(BOOL)animated 274 | { 275 | if (self.slideMenuController.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 276 | { 277 | [self.navigationItem setLeftBarButtonItem:self.leftBarButtonItem animated:animated]; 278 | [self.navigationItem setRightBarButtonItem:nil animated:animated]; 279 | } 280 | else if (self.slideMenuController.slideDirection == NVSlideMenuControllerSlideFromRightToLeft) 281 | { 282 | [self.navigationItem setRightBarButtonItem:self.rightBarButtonItem animated:animated]; 283 | [self.navigationItem setLeftBarButtonItem:nil animated:animated]; 284 | } 285 | } 286 | 287 | 288 | #pragma mark - Rotation 289 | 290 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 291 | { 292 | return toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown; 293 | } 294 | 295 | @end 296 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3727E3A6169709A800AA50DA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3727E3A5169709A800AA50DA /* QuartzCore.framework */; }; 11 | 373F73BA1694238700134653 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 373F73B91694238700134653 /* UIKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 12 | 373F73BC1694238700134653 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 373F73BB1694238700134653 /* Foundation.framework */; }; 13 | 373F73BE1694238700134653 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 373F73BD1694238700134653 /* CoreGraphics.framework */; }; 14 | 373F73C41694238700134653 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 373F73C21694238700134653 /* InfoPlist.strings */; }; 15 | 373F73C61694238700134653 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 373F73C51694238700134653 /* main.m */; }; 16 | 373F73CA1694238700134653 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 373F73C91694238700134653 /* AppDelegate.m */; }; 17 | 373F73CC1694238700134653 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 373F73CB1694238700134653 /* Default.png */; }; 18 | 373F73CE1694238700134653 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 373F73CD1694238700134653 /* Default@2x.png */; }; 19 | 373F73D01694238700134653 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 373F73CF1694238700134653 /* Default-568h@2x.png */; }; 20 | 373F73DC169423CD00134653 /* DetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 373F73D8169423CD00134653 /* DetailsViewController.m */; }; 21 | 373F73DD169423CD00134653 /* DetailsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 373F73D9169423CD00134653 /* DetailsViewController.xib */; }; 22 | 373F73DE169423CD00134653 /* MenuViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 373F73DB169423CD00134653 /* MenuViewController.m */; }; 23 | 37D1DAFA17FF02B800C250D7 /* NVSlideMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 373F73E2169423D600134653 /* NVSlideMenuController.m */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 3727E3A5169709A800AA50DA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 28 | 373F73B51694238700134653 /* BasicDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BasicDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 373F73B91694238700134653 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 30 | 373F73BB1694238700134653 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31 | 373F73BD1694238700134653 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 32 | 373F73C11694238700134653 /* BasicDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BasicDemo-Info.plist"; sourceTree = ""; }; 33 | 373F73C31694238700134653 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 34 | 373F73C51694238700134653 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | 373F73C71694238700134653 /* BasicDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BasicDemo-Prefix.pch"; sourceTree = ""; }; 36 | 373F73C81694238700134653 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 37 | 373F73C91694238700134653 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 38 | 373F73CB1694238700134653 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 39 | 373F73CD1694238700134653 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 40 | 373F73CF1694238700134653 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 41 | 373F73D7169423CD00134653 /* DetailsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetailsViewController.h; sourceTree = ""; }; 42 | 373F73D8169423CD00134653 /* DetailsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DetailsViewController.m; sourceTree = ""; }; 43 | 373F73D9169423CD00134653 /* DetailsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DetailsViewController.xib; sourceTree = ""; }; 44 | 373F73DA169423CD00134653 /* MenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuViewController.h; sourceTree = ""; }; 45 | 373F73DB169423CD00134653 /* MenuViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuViewController.m; sourceTree = ""; }; 46 | 373F73E1169423D600134653 /* NVSlideMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NVSlideMenuController.h; sourceTree = ""; }; 47 | 373F73E2169423D600134653 /* NVSlideMenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NVSlideMenuController.m; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | 373F73B21694238700134653 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | 3727E3A6169709A800AA50DA /* QuartzCore.framework in Frameworks */, 56 | 373F73BA1694238700134653 /* UIKit.framework in Frameworks */, 57 | 373F73BC1694238700134653 /* Foundation.framework in Frameworks */, 58 | 373F73BE1694238700134653 /* CoreGraphics.framework in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 373F73AA1694238700134653 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 373F73BF1694238700134653 /* BasicDemo */, 69 | 373F73B81694238700134653 /* Frameworks */, 70 | 373F73B61694238700134653 /* Products */, 71 | ); 72 | sourceTree = ""; 73 | }; 74 | 373F73B61694238700134653 /* Products */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 373F73B51694238700134653 /* BasicDemo.app */, 78 | ); 79 | name = Products; 80 | sourceTree = ""; 81 | }; 82 | 373F73B81694238700134653 /* Frameworks */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 3727E3A5169709A800AA50DA /* QuartzCore.framework */, 86 | 373F73B91694238700134653 /* UIKit.framework */, 87 | 373F73BB1694238700134653 /* Foundation.framework */, 88 | 373F73BD1694238700134653 /* CoreGraphics.framework */, 89 | ); 90 | name = Frameworks; 91 | sourceTree = ""; 92 | }; 93 | 373F73BF1694238700134653 /* BasicDemo */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 373F73DF169423D600134653 /* lib */, 97 | 373F73C81694238700134653 /* AppDelegate.h */, 98 | 373F73C91694238700134653 /* AppDelegate.m */, 99 | 373F73D6169423CD00134653 /* View Controllers */, 100 | 373F73C01694238700134653 /* Supporting Files */, 101 | ); 102 | path = BasicDemo; 103 | sourceTree = ""; 104 | }; 105 | 373F73C01694238700134653 /* Supporting Files */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 373F73C11694238700134653 /* BasicDemo-Info.plist */, 109 | 373F73C21694238700134653 /* InfoPlist.strings */, 110 | 373F73C51694238700134653 /* main.m */, 111 | 373F73C71694238700134653 /* BasicDemo-Prefix.pch */, 112 | 373F73CB1694238700134653 /* Default.png */, 113 | 373F73CD1694238700134653 /* Default@2x.png */, 114 | 373F73CF1694238700134653 /* Default-568h@2x.png */, 115 | ); 116 | name = "Supporting Files"; 117 | sourceTree = ""; 118 | }; 119 | 373F73D6169423CD00134653 /* View Controllers */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 373F73D7169423CD00134653 /* DetailsViewController.h */, 123 | 373F73D8169423CD00134653 /* DetailsViewController.m */, 124 | 373F73D9169423CD00134653 /* DetailsViewController.xib */, 125 | 373F73DA169423CD00134653 /* MenuViewController.h */, 126 | 373F73DB169423CD00134653 /* MenuViewController.m */, 127 | ); 128 | path = "View Controllers"; 129 | sourceTree = ""; 130 | }; 131 | 373F73DF169423D600134653 /* lib */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 373F73E0169423D600134653 /* NVSlideMenuController */, 135 | ); 136 | name = lib; 137 | path = ../../../lib; 138 | sourceTree = ""; 139 | }; 140 | 373F73E0169423D600134653 /* NVSlideMenuController */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 373F73E1169423D600134653 /* NVSlideMenuController.h */, 144 | 373F73E2169423D600134653 /* NVSlideMenuController.m */, 145 | ); 146 | path = NVSlideMenuController; 147 | sourceTree = ""; 148 | }; 149 | /* End PBXGroup section */ 150 | 151 | /* Begin PBXNativeTarget section */ 152 | 373F73B41694238700134653 /* BasicDemo */ = { 153 | isa = PBXNativeTarget; 154 | buildConfigurationList = 373F73D31694238700134653 /* Build configuration list for PBXNativeTarget "BasicDemo" */; 155 | buildPhases = ( 156 | 373F73B11694238700134653 /* Sources */, 157 | 373F73B21694238700134653 /* Frameworks */, 158 | 373F73B31694238700134653 /* Resources */, 159 | ); 160 | buildRules = ( 161 | ); 162 | dependencies = ( 163 | ); 164 | name = BasicDemo; 165 | productName = NVSlideMenuControllerDemo; 166 | productReference = 373F73B51694238700134653 /* BasicDemo.app */; 167 | productType = "com.apple.product-type.application"; 168 | }; 169 | /* End PBXNativeTarget section */ 170 | 171 | /* Begin PBXProject section */ 172 | 373F73AC1694238700134653 /* Project object */ = { 173 | isa = PBXProject; 174 | attributes = { 175 | LastUpgradeCheck = 0720; 176 | ORGANIZATIONNAME = "Nicolas VERINAUD"; 177 | TargetAttributes = { 178 | 373F73B41694238700134653 = { 179 | DevelopmentTeam = 4C7SPGJ9DJ; 180 | }; 181 | }; 182 | }; 183 | buildConfigurationList = 373F73AF1694238700134653 /* Build configuration list for PBXProject "BasicDemo" */; 184 | compatibilityVersion = "Xcode 3.2"; 185 | developmentRegion = English; 186 | hasScannedForEncodings = 0; 187 | knownRegions = ( 188 | en, 189 | ); 190 | mainGroup = 373F73AA1694238700134653; 191 | productRefGroup = 373F73B61694238700134653 /* Products */; 192 | projectDirPath = ""; 193 | projectRoot = ""; 194 | targets = ( 195 | 373F73B41694238700134653 /* BasicDemo */, 196 | ); 197 | }; 198 | /* End PBXProject section */ 199 | 200 | /* Begin PBXResourcesBuildPhase section */ 201 | 373F73B31694238700134653 /* Resources */ = { 202 | isa = PBXResourcesBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | 373F73C41694238700134653 /* InfoPlist.strings in Resources */, 206 | 373F73CC1694238700134653 /* Default.png in Resources */, 207 | 373F73CE1694238700134653 /* Default@2x.png in Resources */, 208 | 373F73D01694238700134653 /* Default-568h@2x.png in Resources */, 209 | 373F73DD169423CD00134653 /* DetailsViewController.xib in Resources */, 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | }; 213 | /* End PBXResourcesBuildPhase section */ 214 | 215 | /* Begin PBXSourcesBuildPhase section */ 216 | 373F73B11694238700134653 /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 373F73C61694238700134653 /* main.m in Sources */, 221 | 373F73CA1694238700134653 /* AppDelegate.m in Sources */, 222 | 373F73DC169423CD00134653 /* DetailsViewController.m in Sources */, 223 | 37D1DAFA17FF02B800C250D7 /* NVSlideMenuController.m in Sources */, 224 | 373F73DE169423CD00134653 /* MenuViewController.m in Sources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXSourcesBuildPhase section */ 229 | 230 | /* Begin PBXVariantGroup section */ 231 | 373F73C21694238700134653 /* InfoPlist.strings */ = { 232 | isa = PBXVariantGroup; 233 | children = ( 234 | 373F73C31694238700134653 /* en */, 235 | ); 236 | name = InfoPlist.strings; 237 | sourceTree = ""; 238 | }; 239 | /* End PBXVariantGroup section */ 240 | 241 | /* Begin XCBuildConfiguration section */ 242 | 373F73D11694238700134653 /* Debug */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | ALWAYS_SEARCH_USER_PATHS = NO; 246 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 247 | CLANG_CXX_LIBRARY = "libc++"; 248 | CLANG_WARN_EMPTY_BODY = YES; 249 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 250 | COPY_PHASE_STRIP = NO; 251 | ENABLE_TESTABILITY = YES; 252 | GCC_C_LANGUAGE_STANDARD = gnu99; 253 | GCC_DYNAMIC_NO_PIC = NO; 254 | GCC_OPTIMIZATION_LEVEL = 0; 255 | GCC_PREPROCESSOR_DEFINITIONS = ( 256 | "DEBUG=1", 257 | "$(inherited)", 258 | ); 259 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 260 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 261 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 262 | GCC_WARN_UNUSED_VARIABLE = YES; 263 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 264 | ONLY_ACTIVE_ARCH = YES; 265 | SDKROOT = iphoneos; 266 | TARGETED_DEVICE_FAMILY = "1,2"; 267 | }; 268 | name = Debug; 269 | }; 270 | 373F73D21694238700134653 /* Release */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | ALWAYS_SEARCH_USER_PATHS = NO; 274 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 275 | CLANG_CXX_LIBRARY = "libc++"; 276 | CLANG_WARN_EMPTY_BODY = YES; 277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 278 | COPY_PHASE_STRIP = YES; 279 | GCC_C_LANGUAGE_STANDARD = gnu99; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 281 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 282 | GCC_WARN_UNUSED_VARIABLE = YES; 283 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 284 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 285 | SDKROOT = iphoneos; 286 | TARGETED_DEVICE_FAMILY = "1,2"; 287 | VALIDATE_PRODUCT = YES; 288 | }; 289 | name = Release; 290 | }; 291 | 373F73D41694238700134653 /* Debug */ = { 292 | isa = XCBuildConfiguration; 293 | buildSettings = { 294 | CLANG_ENABLE_OBJC_ARC = YES; 295 | CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; 296 | CODE_SIGN_IDENTITY = "iPhone Developer"; 297 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 298 | GCC_PREFIX_HEADER = "BasicDemo/BasicDemo-Prefix.pch"; 299 | INFOPLIST_FILE = "$(SRCROOT)/BasicDemo/BasicDemo-Info.plist"; 300 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 301 | PRODUCT_BUNDLE_IDENTIFIER = "com.nverinaud.${PRODUCT_NAME:rfc1034identifier}"; 302 | PRODUCT_NAME = BasicDemo; 303 | PROVISIONING_PROFILE = ""; 304 | WARNING_CFLAGS = "-Warc-bridge-casts-disallowed-in-nonarc"; 305 | WRAPPER_EXTENSION = app; 306 | }; 307 | name = Debug; 308 | }; 309 | 373F73D51694238700134653 /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | CLANG_ENABLE_OBJC_ARC = YES; 313 | CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; 314 | CODE_SIGN_IDENTITY = "iPhone Developer"; 315 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 316 | GCC_PREFIX_HEADER = "BasicDemo/BasicDemo-Prefix.pch"; 317 | INFOPLIST_FILE = "$(SRCROOT)/BasicDemo/BasicDemo-Info.plist"; 318 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 319 | PRODUCT_BUNDLE_IDENTIFIER = "com.nverinaud.${PRODUCT_NAME:rfc1034identifier}"; 320 | PRODUCT_NAME = BasicDemo; 321 | PROVISIONING_PROFILE = ""; 322 | WARNING_CFLAGS = "-Warc-bridge-casts-disallowed-in-nonarc"; 323 | WRAPPER_EXTENSION = app; 324 | }; 325 | name = Release; 326 | }; 327 | /* End XCBuildConfiguration section */ 328 | 329 | /* Begin XCConfigurationList section */ 330 | 373F73AF1694238700134653 /* Build configuration list for PBXProject "BasicDemo" */ = { 331 | isa = XCConfigurationList; 332 | buildConfigurations = ( 333 | 373F73D11694238700134653 /* Debug */, 334 | 373F73D21694238700134653 /* Release */, 335 | ); 336 | defaultConfigurationIsVisible = 0; 337 | defaultConfigurationName = Release; 338 | }; 339 | 373F73D31694238700134653 /* Build configuration list for PBXNativeTarget "BasicDemo" */ = { 340 | isa = XCConfigurationList; 341 | buildConfigurations = ( 342 | 373F73D41694238700134653 /* Debug */, 343 | 373F73D51694238700134653 /* Release */, 344 | ); 345 | defaultConfigurationIsVisible = 0; 346 | defaultConfigurationName = Release; 347 | }; 348 | /* End XCConfigurationList section */ 349 | }; 350 | rootObject = 373F73AC1694238700134653 /* Project object */; 351 | } 352 | -------------------------------------------------------------------------------- /Demos/Basic/BasicDemo/View Controllers/DetailsViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1552 5 | 12D78 6 | 3084 7 | 1187.37 8 | 626.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 2083 12 | 13 | 14 | IBProxyObject 15 | IBUIBarButtonItem 16 | IBUIButton 17 | IBUILabel 18 | IBUISwitch 19 | IBUITextView 20 | IBUIToolbar 21 | IBUIView 22 | 23 | 24 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 25 | 26 | 27 | PluginDependencyRecalculationVersion 28 | 29 | 30 | 31 | 32 | IBFilesOwner 33 | IBCocoaTouchFramework 34 | 35 | 36 | IBFirstResponder 37 | IBCocoaTouchFramework 38 | 39 | 40 | 41 | 274 42 | 43 | 44 | 45 | 290 46 | {320, 81} 47 | 48 | 49 | 50 | _NS:9 51 | 52 | 1 53 | MSAxIDEAA 54 | 55 | YES 56 | YES 57 | IBCocoaTouchFramework 58 | 59 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. 60 | 61 | 62 | 2 63 | IBCocoaTouchFramework 64 | 65 | 66 | 1 67 | 14 68 | 69 | 70 | Helvetica 71 | 14 72 | 16 73 | 74 | 75 | 76 | 77 | 293 78 | {{66, 89}, {189, 44}} 79 | 80 | 81 | 82 | _NS:9 83 | NO 84 | IBCocoaTouchFramework 85 | 0 86 | 0 87 | 1 88 | Show Menu ! 89 | 90 | 3 91 | MQA 92 | 93 | 94 | 1 95 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 96 | 97 | 98 | 3 99 | MC41AA 100 | 101 | 102 | 2 103 | 15 104 | 105 | 106 | Helvetica-Bold 107 | 15 108 | 16 109 | 110 | 111 | 112 | 113 | 293 114 | {{66, 140}, {189, 44}} 115 | 116 | 117 | 118 | _NS:9 119 | NO 120 | IBCocoaTouchFramework 121 | 0 122 | 0 123 | 1 124 | Change Slide Direction 125 | 126 | 127 | 1 128 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 289 137 | {{208, 191}, {94, 27}} 138 | 139 | 140 | 141 | _NS:9 142 | NO 143 | IBCocoaTouchFramework 144 | 0 145 | 0 146 | 147 | 148 | 149 | 294 150 | {{20, 194}, {195, 21}} 151 | 152 | 153 | 154 | _NS:9 155 | NO 156 | YES 157 | 7 158 | NO 159 | IBCocoaTouchFramework 160 | Bounce when navigating 161 | 162 | 1 163 | MCAwIDAAA 164 | darkTextColor 165 | 166 | 167 | 0 168 | 169 | 1 170 | 17 171 | 172 | 173 | Helvetica 174 | 17 175 | 16 176 | 177 | NO 178 | 179 | 180 | 181 | 289 182 | {{208, 223}, {94, 27}} 183 | 184 | 185 | 186 | _NS:9 187 | NO 188 | IBCocoaTouchFramework 189 | 0 190 | 0 191 | 192 | 193 | 194 | 294 195 | {{20, 226}, {195, 21}} 196 | 197 | 198 | 199 | _NS:9 200 | NO 201 | YES 202 | 7 203 | NO 204 | IBCocoaTouchFramework 205 | Auto adjust menu width 206 | 207 | 208 | 0 209 | 210 | 211 | NO 212 | 213 | 214 | {{0, 20}, {320, 548}} 215 | 216 | 217 | 218 | 219 | 3 220 | MQA 221 | 222 | 2 223 | 224 | 225 | 226 | 227 | IBUIScreenMetrics 228 | 229 | YES 230 | 231 | 232 | 233 | 234 | 235 | {320, 568} 236 | {568, 320} 237 | 238 | 239 | IBCocoaTouchFramework 240 | Retina 4 Full Screen 241 | 2 242 | 243 | IBCocoaTouchFramework 244 | 245 | 246 | 247 | 266 248 | {320, 44} 249 | 250 | 251 | 252 | _NS:9 253 | NO 254 | NO 255 | IBCocoaTouchFramework 256 | 2 257 | 258 | 259 | IBCocoaTouchFramework 260 | 261 | 5 262 | 263 | 264 | IBCocoaTouchFramework 265 | 2 266 | 267 | 0 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | view 277 | 278 | 279 | 280 | 3 281 | 282 | 283 | 284 | textView 285 | 286 | 287 | 288 | 12 289 | 290 | 291 | 292 | bounceSwitch 293 | 294 | 295 | 296 | 20 297 | 298 | 299 | 300 | menuWidthSwitch 301 | 302 | 303 | 304 | 24 305 | 306 | 307 | 308 | toolbar 309 | 310 | 311 | 312 | 29 313 | 314 | 315 | 316 | showMenu: 317 | 318 | 319 | 7 320 | 321 | 14 322 | 323 | 324 | 325 | changeSlideDirection: 326 | 327 | 328 | 7 329 | 330 | 16 331 | 332 | 333 | 334 | bounceSwitchValueChanged: 335 | 336 | 337 | 13 338 | 339 | 19 340 | 341 | 342 | 343 | menuWidthSwitchValueChanged: 344 | 345 | 346 | 13 347 | 348 | 25 349 | 350 | 351 | 352 | hideKeyboard: 353 | 354 | 355 | 356 | 30 357 | 358 | 359 | 360 | 361 | 362 | 0 363 | 364 | 365 | 366 | 367 | 368 | 1 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | -1 383 | 384 | 385 | File's Owner 386 | 387 | 388 | -2 389 | 390 | 391 | 392 | 393 | 7 394 | 395 | 396 | 397 | 398 | 13 399 | 400 | 401 | 402 | 403 | 15 404 | 405 | 406 | 407 | 408 | 17 409 | 410 | 411 | 412 | 413 | 18 414 | 415 | 416 | 417 | 418 | 21 419 | 420 | 421 | 422 | 423 | 22 424 | 425 | 426 | 427 | 428 | 26 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 27 438 | 439 | 440 | 441 | 442 | 28 443 | 444 | 445 | 446 | 447 | 448 | 449 | DetailsViewController 450 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 451 | UIResponder 452 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 453 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 454 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 455 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 456 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 457 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 458 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 459 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 460 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 461 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 462 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 463 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 464 | 465 | 466 | 467 | 468 | 469 | 30 470 | 471 | 472 | 473 | 474 | DetailsViewController 475 | UIViewController 476 | 477 | id 478 | id 479 | id 480 | id 481 | id 482 | 483 | 484 | 485 | bounceSwitchValueChanged: 486 | id 487 | 488 | 489 | changeSlideDirection: 490 | id 491 | 492 | 493 | hideKeyboard: 494 | id 495 | 496 | 497 | menuWidthSwitchValueChanged: 498 | id 499 | 500 | 501 | showMenu: 502 | id 503 | 504 | 505 | 506 | UISwitch 507 | UISwitch 508 | UITextView 509 | UIToolbar 510 | 511 | 512 | 513 | bounceSwitch 514 | UISwitch 515 | 516 | 517 | menuWidthSwitch 518 | UISwitch 519 | 520 | 521 | textView 522 | UITextView 523 | 524 | 525 | toolbar 526 | UIToolbar 527 | 528 | 529 | 530 | IBProjectSource 531 | ./Classes/DetailsViewController.h 532 | 533 | 534 | 535 | 536 | 0 537 | IBCocoaTouchFramework 538 | YES 539 | 3 540 | 2083 541 | 542 | 543 | -------------------------------------------------------------------------------- /lib/NVSlideMenuController/NVSlideMenuController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NVSlideMenuViewController.m 3 | // NVSlideMenuViewController 4 | // 5 | // Created by Nicolas Verinaud on 31/12/12. 6 | // Copyright (c) 2012 Nicolas Verinaud. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NVSlideMenuController.h" 11 | 12 | #ifdef __has_feature 13 | #define OBJC_ARC_ENABLED __has_feature(objc_arc) 14 | #else 15 | #define OBJC_ARC_ENABLED 0 16 | #endif 17 | 18 | 19 | #define ANIMATION_DURATION 0.3f 20 | #define BOUNCE_DURATION 0.3f 21 | 22 | @interface NVSlideMenuController () 23 | { 24 | CGFloat _contentViewWidthWhenMenuIsOpen; 25 | } 26 | 27 | /** Children view controllers */ 28 | @property (nonatomic, readwrite, strong) UIViewController *menuViewController; 29 | @property (nonatomic, readwrite, strong) UIViewController *contentViewController; 30 | 31 | /** Shadow */ 32 | - (void)setShadowOnContentView; 33 | - (void)removeShadowOnContentView; 34 | - (CGSize)shadowOffsetAccordingToCurrentSlideDirection; 35 | 36 | /** 37 | Load the menu view controller view and add its view as a subview 38 | to self.view with correct frame. 39 | */ 40 | - (void)loadMenuViewControllerViewIfNeeded; 41 | 42 | /** Gesture recognizers */ 43 | @property (nonatomic, strong) UITapGestureRecognizer *tapGesture; 44 | - (void)tapGestureTriggered:(UITapGestureRecognizer *)tapGesture; 45 | 46 | @property (nonatomic, assign) CGRect contentViewControllerFrame; 47 | @property (nonatomic, assign) BOOL menuWasOpenAtPanBegin; 48 | @property (nonatomic, strong) UIPanGestureRecognizer *panGesture; 49 | - (void)panGestureTriggered:(UIPanGestureRecognizer *)panGesture; 50 | 51 | /** Utils */ 52 | - (CGFloat)contentViewMinX; 53 | - (CGRect)menuViewFrameAccordingToCurrentSlideDirection; 54 | - (UIViewAutoresizing)menuViewAutoresizingMaskAccordingToCurrentSlideDirection; 55 | 56 | 57 | /** State */ 58 | @property (nonatomic, assign, getter = isContentViewHidden) BOOL contentViewHidden; 59 | 60 | @end 61 | 62 | 63 | @implementation NVSlideMenuController 64 | 65 | #pragma mark - Memory Management 66 | 67 | #if !OBJC_ARC_ENABLED 68 | - (void)dealloc 69 | { 70 | [_menuViewController release]; 71 | [_contentViewController release]; 72 | 73 | [_tapGesture release]; 74 | [_panGesture release]; 75 | 76 | [super dealloc]; 77 | } 78 | #endif 79 | 80 | 81 | #pragma mark - Creation 82 | #pragma mark Designated Initializer 83 | 84 | - (id)initWithMenuViewController:(UIViewController *)menuViewController andContentViewController:(UIViewController *)contentViewController 85 | { 86 | self = [super initWithNibName:nil bundle:nil]; 87 | if (self) 88 | { 89 | self.menuViewController = menuViewController; 90 | self.contentViewController = contentViewController; 91 | self.panGestureEnabled = YES; 92 | self.slideDirection = NVSlideMenuControllerSlideFromLeftToRight; 93 | _contentViewWidthWhenMenuIsOpen = -1; 94 | self.menuWidth = 276; 95 | self.autoAdjustMenuWidth = YES; 96 | self.showShadowOnContentView = YES; 97 | } 98 | 99 | return self; 100 | } 101 | 102 | #pragma mark Overriden Initializers 103 | 104 | - (id)initWithCoder:(NSCoder *)aDecoder 105 | { 106 | self = [super initWithCoder:aDecoder]; 107 | if (self) 108 | { 109 | self.menuViewController = nil; 110 | self.contentViewController = nil; 111 | self.panGestureEnabled = YES; 112 | self.slideDirection = NVSlideMenuControllerSlideFromLeftToRight; 113 | self.autoAdjustMenuWidth = YES; 114 | self.showShadowOnContentView = YES; 115 | } 116 | 117 | return self; 118 | } 119 | 120 | 121 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 122 | { 123 | return [self initWithMenuViewController:nil andContentViewController:nil]; 124 | } 125 | 126 | 127 | #pragma mark - Children View Controllers 128 | 129 | - (void)setMenuViewController:(UIViewController *)menuViewController 130 | { 131 | if (menuViewController != _menuViewController) 132 | { 133 | [_menuViewController willMoveToParentViewController:nil]; 134 | [_menuViewController removeFromParentViewController]; 135 | 136 | #if !OBJC_ARC_ENABLED 137 | [_menuViewController release]; 138 | _menuViewController = [menuViewController retain]; 139 | #else 140 | _menuViewController = menuViewController; 141 | #endif 142 | } 143 | } 144 | 145 | 146 | - (void)setContentViewController:(UIViewController *)contentViewController 147 | { 148 | if (contentViewController != _contentViewController) 149 | { 150 | [_contentViewController willMoveToParentViewController:nil]; 151 | [_contentViewController removeFromParentViewController]; 152 | 153 | #if !OBJC_ARC_ENABLED 154 | [_contentViewController release]; 155 | _contentViewController = [contentViewController retain]; 156 | #else 157 | _contentViewController = contentViewController; 158 | #endif 159 | } 160 | } 161 | 162 | 163 | #pragma mark - View lifecycle 164 | 165 | - (void)viewDidLoad 166 | { 167 | [super viewDidLoad]; 168 | 169 | if (_contentViewWidthWhenMenuIsOpen >= 0) 170 | self.menuWidth = CGRectGetWidth(self.view.bounds) - _contentViewWidthWhenMenuIsOpen; 171 | 172 | [self addChildViewController:self.contentViewController]; 173 | self.contentViewController.view.frame = self.view.bounds; 174 | [self.view addSubview:self.contentViewController.view]; 175 | [self.contentViewController didMoveToParentViewController:self]; 176 | 177 | [self setShadowOnContentView]; 178 | 179 | [self.contentViewController.view addGestureRecognizer:self.tapGesture]; 180 | self.tapGesture.enabled = NO; 181 | [self.contentViewController.view addGestureRecognizer:self.panGesture]; 182 | } 183 | 184 | 185 | - (void)viewWillAppear:(BOOL)animated 186 | { 187 | [super viewWillAppear:animated]; 188 | 189 | if (![self isMenuOpen]) 190 | self.contentViewController.view.frame = self.view.bounds; 191 | 192 | [self.contentViewController beginAppearanceTransition:YES animated:animated]; 193 | if ([self.menuViewController isViewLoaded] && self.menuViewController.view.superview) 194 | [self.menuViewController beginAppearanceTransition:YES animated:animated]; 195 | } 196 | 197 | 198 | - (void)viewDidAppear:(BOOL)animated 199 | { 200 | [super viewDidAppear:animated]; 201 | 202 | [self.contentViewController endAppearanceTransition]; 203 | if ([self.menuViewController isViewLoaded] && self.menuViewController.view.superview) 204 | [self.menuViewController endAppearanceTransition]; 205 | } 206 | 207 | 208 | - (void)viewWillDisappear:(BOOL)animated 209 | { 210 | [super viewWillDisappear:animated]; 211 | 212 | [self.contentViewController beginAppearanceTransition:NO animated:animated]; 213 | if ([self.menuViewController isViewLoaded]) 214 | [self.menuViewController beginAppearanceTransition:NO animated:animated]; 215 | } 216 | 217 | 218 | - (void)viewDidDisappear:(BOOL)animated 219 | { 220 | [super viewDidDisappear:animated]; 221 | 222 | [self.contentViewController endAppearanceTransition]; 223 | if ([self.menuViewController isViewLoaded]) 224 | [self.menuViewController endAppearanceTransition]; 225 | } 226 | 227 | 228 | #pragma mark - Appearance & rotation callbacks 229 | 230 | - (BOOL)shouldAutomaticallyForwardAppearanceMethods 231 | { 232 | return NO; 233 | } 234 | 235 | 236 | - (BOOL)shouldAutomaticallyForwardRotationMethods 237 | { 238 | return YES; 239 | } 240 | 241 | 242 | - (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers 243 | { 244 | return NO; 245 | } 246 | 247 | 248 | - (UIStatusBarStyle)preferredStatusBarStyle 249 | { 250 | UIViewController *vc = self.contentViewController; 251 | 252 | if ([self isMenuOpen]) 253 | vc = self.menuViewController; 254 | 255 | return [vc preferredStatusBarStyle]; 256 | } 257 | 258 | 259 | - (UIViewController *)childViewControllerForStatusBarStyle 260 | { 261 | UIViewController *vc = self.contentViewController; 262 | 263 | if ([self isMenuOpen]) 264 | vc = self.menuViewController; 265 | 266 | return vc; 267 | } 268 | 269 | 270 | - (UIViewController *)childViewControllerForStatusBarHidden 271 | { 272 | UIViewController *vc = self.contentViewController; 273 | 274 | if ([self isMenuOpen]) 275 | vc = self.menuViewController; 276 | 277 | return vc; 278 | } 279 | 280 | 281 | #pragma mark - Rotation 282 | 283 | - (BOOL)shouldAutorotate 284 | { 285 | return [self.menuViewController shouldAutorotate] && 286 | [self.contentViewController shouldAutorotate] && 287 | self.panGesture.state != UIGestureRecognizerStateChanged; 288 | } 289 | 290 | 291 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations 292 | { 293 | return [self.menuViewController supportedInterfaceOrientations] & [self.contentViewController supportedInterfaceOrientations]; 294 | } 295 | 296 | 297 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 298 | { 299 | return [self.menuViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation] && 300 | [self.contentViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation]; 301 | } 302 | 303 | 304 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 305 | { 306 | [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; 307 | 308 | if ([self isMenuOpen]) 309 | { 310 | CGRect frame = self.contentViewController.view.frame; 311 | frame.origin.x = [self contentViewMinX]; 312 | self.contentViewController.view.frame = frame; 313 | 314 | if (![self isContentViewHidden]) 315 | { 316 | // Fix weird shadow behavior according to this post : http://blog.radi.ws/post/8348898129/calayers-shadowpath-and-uiview-autoresizing 317 | CALayer *layer = self.contentViewController.view.layer; 318 | CGPathRef oldShadowPath = layer.shadowPath; 319 | 320 | if (oldShadowPath) 321 | CFRetain(oldShadowPath); 322 | 323 | [self setShadowOnContentView]; 324 | 325 | if (oldShadowPath) 326 | { 327 | CABasicAnimation *transition = [CABasicAnimation animationWithKeyPath:@"shadowPath"]; 328 | #if !OBJC_ARC_ENABLED 329 | transition.fromValue = (id)oldShadowPath; 330 | #else 331 | transition.fromValue = (__bridge id)oldShadowPath; 332 | #endif 333 | 334 | transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 335 | transition.duration = duration; 336 | [layer addAnimation:transition forKey:@"transition"]; 337 | 338 | CFRelease(oldShadowPath); 339 | } 340 | } 341 | } 342 | } 343 | 344 | 345 | #pragma mark - Shadow 346 | 347 | - (void)setShowShadowOnContentView:(BOOL)showShadowOnContentView 348 | { 349 | if (showShadowOnContentView != _showShadowOnContentView) 350 | { 351 | _showShadowOnContentView = showShadowOnContentView; 352 | 353 | if ([self.contentViewController isViewLoaded]) 354 | { 355 | if (_showShadowOnContentView) 356 | [self setShadowOnContentView]; 357 | else if (!_showShadowOnContentView) 358 | [self removeShadowOnContentView]; 359 | } 360 | } 361 | } 362 | 363 | 364 | - (void)setShadowOnContentView 365 | { 366 | if ([self showShadowOnContentView]) 367 | { 368 | UIView *contentView = self.contentViewController.view; 369 | CALayer *layer = contentView.layer; 370 | layer.masksToBounds = NO; 371 | layer.shadowColor = [[UIColor blackColor] CGColor]; 372 | layer.shadowOpacity = 1.f; 373 | layer.shadowRadius = 5.f; 374 | layer.shadowPath = [[UIBezierPath bezierPathWithRect:contentView.bounds] CGPath]; 375 | layer.shadowOffset = [self shadowOffsetAccordingToCurrentSlideDirection]; 376 | } 377 | } 378 | 379 | 380 | - (void)removeShadowOnContentView 381 | { 382 | UIView *contentView = self.contentViewController.view; 383 | CALayer *layer = contentView.layer; 384 | layer.masksToBounds = YES; 385 | } 386 | 387 | 388 | - (CGSize)shadowOffsetAccordingToCurrentSlideDirection 389 | { 390 | if (self.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 391 | return CGSizeMake(-2.5f, 3.f); 392 | else if (self.slideDirection == NVSlideMenuControllerSlideFromRightToLeft) 393 | return CGSizeMake(2.5f, 3.f); 394 | 395 | return CGSizeZero; 396 | } 397 | 398 | 399 | #pragma mark - Slide Direction 400 | 401 | - (void)setSlideDirection:(NVSlideMenuControllerSlideDirection)slideDirection 402 | { 403 | [self setSlideDirection:slideDirection animated:NO]; 404 | } 405 | 406 | 407 | - (void)setSlideDirection:(NVSlideMenuControllerSlideDirection)slideDirection animated:(BOOL)animated 408 | { 409 | if (slideDirection != _slideDirection) 410 | { 411 | _slideDirection = slideDirection; 412 | 413 | if ([self.menuViewController isViewLoaded] && [self.contentViewController isViewLoaded]) 414 | { 415 | self.menuViewController.view.autoresizingMask = [self menuViewAutoresizingMaskAccordingToCurrentSlideDirection]; 416 | 417 | BOOL menuIsOpen = [self isMenuOpen]; 418 | NSTimeInterval duration = (animated && menuIsOpen) ? ANIMATION_DURATION*1.5 : 0; 419 | CGRect targetedContentViewFrame = self.view.bounds; 420 | if (menuIsOpen) 421 | targetedContentViewFrame.origin.x = [self contentViewMinX]; 422 | 423 | [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 424 | 425 | self.menuViewController.view.frame = [self menuViewFrameAccordingToCurrentSlideDirection]; 426 | self.contentViewController.view.frame = targetedContentViewFrame; 427 | 428 | if (![self isContentViewHidden]) 429 | [self setShadowOnContentView]; 430 | 431 | } completion:nil]; 432 | } 433 | } 434 | } 435 | 436 | 437 | #pragma mark - Menu view lazy load 438 | 439 | - (void)loadMenuViewControllerViewIfNeeded 440 | { 441 | if (!self.menuViewController.view.window) 442 | { 443 | [self addChildViewController:self.menuViewController]; 444 | self.menuViewController.view.frame = [self menuViewFrameAccordingToCurrentSlideDirection]; 445 | self.menuViewController.view.autoresizingMask = [self menuViewAutoresizingMaskAccordingToCurrentSlideDirection]; 446 | [self.view insertSubview:self.menuViewController.view atIndex:0]; 447 | [self.menuViewController didMoveToParentViewController:self]; 448 | } 449 | } 450 | 451 | 452 | #pragma mark - Navigation 453 | 454 | - (IBAction)toggleMenuAnimated:(id)sender 455 | { 456 | if ([self isMenuOpen]) 457 | [self closeMenuAnimated:YES completion:nil]; 458 | else 459 | [self openMenuAnimated:YES completion:nil]; 460 | } 461 | 462 | 463 | - (void)openMenuAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion 464 | { 465 | NSTimeInterval duration = animated ? ANIMATION_DURATION : 0; 466 | 467 | UIView *contentView = self.contentViewController.view; 468 | CGRect contentViewFrame = contentView.frame; 469 | contentViewFrame.origin.x = [self contentViewMinX]; 470 | 471 | [self loadMenuViewControllerViewIfNeeded]; 472 | [self.menuViewController beginAppearanceTransition:YES animated:animated]; 473 | [self.contentViewController viewWillSlideOut:animated inSlideMenuController:self]; 474 | 475 | [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 476 | contentView.frame = contentViewFrame; 477 | [self setShadowOnContentView]; 478 | self.menuViewController.view.frame = [self menuViewFrameAccordingToCurrentSlideDirection]; 479 | } completion:^(BOOL finished) { 480 | [self.menuViewController endAppearanceTransition]; 481 | 482 | if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) 483 | [self setNeedsStatusBarAppearanceUpdate]; 484 | 485 | [self.contentViewController viewDidSlideOut:animated inSlideMenuController:self]; 486 | 487 | self.tapGesture.enabled = YES; 488 | 489 | if (completion) 490 | completion(finished); 491 | }]; 492 | } 493 | 494 | 495 | - (void)closeMenuAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion 496 | { 497 | if ([self isMenuOpen]) 498 | { 499 | // Remove gestures 500 | self.tapGesture.enabled = NO; 501 | 502 | self.menuViewController.view.userInteractionEnabled = NO; 503 | 504 | NSTimeInterval duration = animated ? ANIMATION_DURATION : 0; 505 | 506 | UIView *contentView = self.contentViewController.view; 507 | CGRect contentViewFrame = contentView.frame; 508 | contentViewFrame.origin.x = 0; 509 | 510 | [self loadMenuViewControllerViewIfNeeded]; 511 | [self.menuViewController beginAppearanceTransition:NO animated:animated]; 512 | [self.contentViewController viewWillSlideIn:animated inSlideMenuController:self]; 513 | 514 | [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 515 | contentView.frame = contentViewFrame; 516 | } completion:^(BOOL finished) { 517 | [self.menuViewController endAppearanceTransition]; 518 | 519 | if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) 520 | [self setNeedsStatusBarAppearanceUpdate]; 521 | 522 | [self.contentViewController viewDidSlideIn:animated inSlideMenuController:self]; 523 | self.contentViewHidden = NO; 524 | 525 | self.menuViewController.view.userInteractionEnabled = YES; 526 | 527 | if (completion) 528 | completion(finished); 529 | }]; 530 | } 531 | else 532 | { 533 | if (completion) 534 | completion(YES); 535 | } 536 | } 537 | 538 | 539 | - (void)closeMenuBehindContentViewController:(UIViewController *)contentViewController animated:(BOOL)animated completion:(void(^)(BOOL finished))completion 540 | { 541 | [self closeMenuBehindContentViewController:contentViewController animated:animated bounce:self.bounceWhenNavigating completion:completion]; 542 | } 543 | 544 | 545 | - (void)closeMenuBehindContentViewController:(UIViewController *)contentViewController animated:(BOOL)animated bounce:(BOOL)bounce completion:(void(^)(BOOL finished))completion 546 | { 547 | NSAssert(contentViewController != nil, @"Can't show a nil content view controller."); 548 | 549 | void (^swapContentViewController)() = nil; 550 | 551 | if (contentViewController != self.contentViewController) 552 | { 553 | swapContentViewController = ^{ 554 | // Preserve the frame 555 | CGRect frame = self.contentViewController.view.frame; 556 | 557 | // Remove old content view 558 | [self.contentViewController.view removeGestureRecognizer:self.tapGesture]; 559 | [self.contentViewController.view removeGestureRecognizer:self.panGesture]; 560 | 561 | BOOL contentViewWasAlreadyHidden = [self isContentViewHidden]; 562 | if (!contentViewWasAlreadyHidden) 563 | [self.contentViewController beginAppearanceTransition:NO animated:NO]; 564 | 565 | [self.contentViewController willMoveToParentViewController:nil]; 566 | [self.contentViewController.view removeFromSuperview]; 567 | [self.contentViewController removeFromParentViewController]; 568 | 569 | if (!contentViewWasAlreadyHidden) 570 | [self.contentViewController endAppearanceTransition]; 571 | 572 | // Add the new content view 573 | self.contentViewController = contentViewController; 574 | self.contentViewController.view.frame = frame; 575 | [self.contentViewController.view addGestureRecognizer:self.tapGesture]; 576 | [self.contentViewController.view addGestureRecognizer:self.panGesture]; 577 | [self setShadowOnContentView]; 578 | [self.contentViewController beginAppearanceTransition:YES animated:NO]; 579 | [self addChildViewController:self.contentViewController]; 580 | [self.view addSubview:self.contentViewController.view]; 581 | [self.contentViewController didMoveToParentViewController:self]; 582 | [self.contentViewController endAppearanceTransition]; 583 | }; 584 | } 585 | 586 | if (bounce && animated && ![self isContentViewHidden]) 587 | { 588 | CGFloat offScreenDistance = 10.0f; 589 | CGFloat bounceDistance = offScreenDistance + CGRectGetWidth(self.contentViewController.view.bounds) - self.menuWidth; 590 | 591 | //Invert the bounce distance if needed for the slide direction 592 | if (self.slideDirection == NVSlideMenuControllerSlideFromRightToLeft) 593 | bounceDistance *= -1; 594 | 595 | UIView *contentView = self.contentViewController.view; 596 | CGRect contentBounceFrame = contentView.frame; 597 | contentBounceFrame.origin.x += bounceDistance; 598 | 599 | CGRect menuBounceFrame = self.menuViewController.view.frame; 600 | menuBounceFrame.size.width += bounceDistance; 601 | 602 | [UIView animateWithDuration:BOUNCE_DURATION delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 603 | contentView.frame = contentBounceFrame; 604 | self.menuViewController.view.frame = menuBounceFrame; 605 | } completion:^(BOOL finished) { 606 | if (swapContentViewController) 607 | swapContentViewController(); 608 | 609 | [self closeMenuAnimated:animated completion:completion]; 610 | }]; 611 | 612 | } 613 | else 614 | { 615 | if (swapContentViewController) 616 | swapContentViewController(); 617 | 618 | // Perform the close animation 619 | [self closeMenuAnimated:animated completion:completion]; 620 | } 621 | } 622 | 623 | 624 | - (void)hideContentViewControllerAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion 625 | { 626 | if (![self isContentViewHidden]) 627 | { 628 | NSTimeInterval duration = animated ? ANIMATION_DURATION/2 : 0; 629 | BOOL menuIsOpen = [self isMenuOpen]; 630 | UIView *contentView = self.contentViewController.view; 631 | CGRect contentViewFrame = contentView.frame; 632 | 633 | self.contentViewHidden = YES; 634 | contentViewFrame.origin.x = [self contentViewMinX]; 635 | 636 | [self loadMenuViewControllerViewIfNeeded]; 637 | 638 | if (!menuIsOpen) 639 | [self.menuViewController beginAppearanceTransition:YES animated:animated]; 640 | 641 | [self.contentViewController beginAppearanceTransition:NO animated:animated]; 642 | 643 | [UIView animateWithDuration:duration animations:^{ 644 | contentView.frame = contentViewFrame; 645 | [self removeShadowOnContentView]; 646 | self.menuViewController.view.frame = self.view.bounds; 647 | } completion:^(BOOL finished) { 648 | if (!menuIsOpen) 649 | [self.menuViewController endAppearanceTransition]; 650 | 651 | [self.contentViewController endAppearanceTransition]; 652 | 653 | if (completion) 654 | completion(finished); 655 | }]; 656 | } 657 | } 658 | 659 | 660 | - (void)partiallyShowContentViewControllerAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion 661 | { 662 | if ([self isContentViewHidden]) 663 | { 664 | NSTimeInterval duration = animated ? ANIMATION_DURATION/2 : 0; 665 | UIView *contentView = self.contentViewController.view; 666 | CGRect contentViewFrame = contentView.frame; 667 | 668 | self.contentViewHidden = NO; 669 | contentViewFrame.origin.x = [self contentViewMinX]; 670 | 671 | [self.contentViewController beginAppearanceTransition:YES animated:animated]; 672 | 673 | [UIView animateWithDuration:duration animations:^{ 674 | contentView.frame = contentViewFrame; 675 | [self setShadowOnContentView]; 676 | self.menuViewController.view.frame = [self menuViewFrameAccordingToCurrentSlideDirection]; 677 | } completion:^(BOOL finished) { 678 | [self.contentViewController endAppearanceTransition]; 679 | 680 | if (completion) 681 | completion(finished); 682 | }]; 683 | } 684 | } 685 | 686 | 687 | #pragma mark - Gestures 688 | 689 | - (UITapGestureRecognizer *)tapGesture 690 | { 691 | if (!_tapGesture) 692 | _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureTriggered:)]; 693 | 694 | return _tapGesture; 695 | } 696 | 697 | 698 | - (void)tapGestureTriggered:(UITapGestureRecognizer *)tapGesture 699 | { 700 | if (tapGesture.state == UIGestureRecognizerStateEnded) 701 | [self closeMenuAnimated:YES completion:nil]; 702 | } 703 | 704 | 705 | - (UIPanGestureRecognizer *)panGesture 706 | { 707 | if (!_panGesture) 708 | _panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureTriggered:)]; 709 | 710 | return _panGesture; 711 | } 712 | 713 | 714 | - (void)setPanGestureEnabled:(BOOL)panGestureEnabled 715 | { 716 | self.panGesture.enabled = panGestureEnabled; 717 | } 718 | 719 | 720 | - (BOOL)panGestureEnabled 721 | { 722 | return self.panGesture.enabled; 723 | } 724 | 725 | 726 | - (void)panGestureTriggered:(UIPanGestureRecognizer *)panGesture 727 | { 728 | if (panGesture.state == UIGestureRecognizerStateBegan) 729 | { 730 | self.contentViewControllerFrame = self.contentViewController.view.frame; 731 | self.menuWasOpenAtPanBegin = [self isMenuOpen]; 732 | 733 | if (!self.menuWasOpenAtPanBegin) 734 | { 735 | [self loadMenuViewControllerViewIfNeeded]; // Menu is closed, load it if needed 736 | [self.menuViewController beginAppearanceTransition:YES animated:YES]; // Menu is appearing 737 | [self.contentViewController viewWillSlideOut:YES inSlideMenuController:self]; // Content view controller is sliding out 738 | } 739 | else 740 | { 741 | [self.contentViewController viewWillSlideIn:YES inSlideMenuController:self]; 742 | } 743 | } 744 | 745 | CGPoint translation = [panGesture translationInView:panGesture.view]; 746 | 747 | CGRect frame = self.contentViewControllerFrame; 748 | CGFloat contentViewMinX = [self contentViewMinX]; 749 | 750 | if (self.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 751 | { 752 | frame.origin.x += translation.x; 753 | 754 | if (frame.origin.x > contentViewMinX) 755 | frame.origin.x = contentViewMinX; 756 | else if (frame.origin.x < 0) 757 | frame.origin.x = 0; 758 | } 759 | else 760 | { 761 | frame.origin.x += translation.x; 762 | 763 | if (frame.origin.x < contentViewMinX) 764 | frame.origin.x = contentViewMinX; 765 | else if (frame.origin.x > 0) 766 | frame.origin.x = 0; 767 | } 768 | 769 | panGesture.view.frame = frame; 770 | 771 | if (panGesture.state == UIGestureRecognizerStateEnded) 772 | { 773 | CGPoint velocity = [panGesture velocityInView:panGesture.view]; 774 | CGFloat distance = 0; 775 | NSTimeInterval animationDuration = 0; 776 | 777 | BOOL close = NO; 778 | if (self.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 779 | close = (velocity.x < 0); 780 | else 781 | close = (velocity.x > 0); 782 | 783 | if (close) // Close 784 | { 785 | // Compute animation duration 786 | distance = frame.origin.x; 787 | animationDuration = fabs(distance / velocity.x); 788 | if (animationDuration > ANIMATION_DURATION) 789 | animationDuration = ANIMATION_DURATION; 790 | 791 | // Remove gestures 792 | self.tapGesture.enabled = NO; 793 | 794 | frame.origin.x = 0; 795 | 796 | if (!self.menuWasOpenAtPanBegin) 797 | { 798 | [self.menuViewController endAppearanceTransition]; 799 | [self.contentViewController viewDidSlideOut:YES inSlideMenuController:self]; 800 | [self.contentViewController viewWillSlideIn:YES inSlideMenuController:self]; 801 | } 802 | 803 | [self.menuViewController beginAppearanceTransition:NO animated:YES]; 804 | 805 | [UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 806 | self.contentViewController.view.frame = frame; 807 | } completion:^(BOOL finished) { 808 | [self.menuViewController endAppearanceTransition]; 809 | 810 | if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) 811 | [self setNeedsStatusBarAppearanceUpdate]; 812 | 813 | [self.contentViewController viewDidSlideIn:YES inSlideMenuController:self]; 814 | }]; 815 | } 816 | else // Open 817 | { 818 | distance = fabs(contentViewMinX - frame.origin.x); 819 | animationDuration = fabs(distance / velocity.x); 820 | if (animationDuration > ANIMATION_DURATION) 821 | animationDuration = ANIMATION_DURATION; 822 | 823 | frame.origin.x = contentViewMinX; 824 | 825 | if (self.menuWasOpenAtPanBegin) 826 | { 827 | [self.contentViewController viewDidSlideIn:YES inSlideMenuController:self]; 828 | [self.contentViewController viewWillSlideOut:YES inSlideMenuController:self]; 829 | } 830 | 831 | [UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 832 | self.contentViewController.view.frame = frame; 833 | } completion:^(BOOL finished) { 834 | self.tapGesture.enabled = YES; 835 | 836 | if (!self.menuWasOpenAtPanBegin) 837 | [self.menuViewController endAppearanceTransition]; 838 | 839 | if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) 840 | [self setNeedsStatusBarAppearanceUpdate]; 841 | 842 | [self.contentViewController viewDidSlideOut:YES inSlideMenuController:self]; 843 | }]; 844 | } 845 | 846 | self.contentViewControllerFrame = frame; 847 | } 848 | } 849 | 850 | 851 | #pragma mark - Menu State 852 | 853 | - (BOOL)isMenuOpen 854 | { 855 | if ([self.contentViewController isViewLoaded]) 856 | return self.contentViewController.view.frame.origin.x != 0; 857 | 858 | return NO; 859 | } 860 | 861 | 862 | #pragma mark - Utils 863 | 864 | - (CGFloat)contentViewMinX 865 | { 866 | CGFloat minX = 0; 867 | 868 | if ([self isContentViewHidden]) 869 | { 870 | if (self.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 871 | minX = CGRectGetWidth(self.view.bounds); 872 | else 873 | minX = -CGRectGetWidth(self.view.bounds); 874 | } 875 | else 876 | { 877 | if (self.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 878 | minX = self.menuWidth; 879 | else 880 | minX = -self.menuWidth; 881 | } 882 | 883 | return minX; 884 | } 885 | 886 | 887 | - (CGRect)menuViewFrameAccordingToCurrentSlideDirection 888 | { 889 | CGRect menuFrame = self.view.bounds; 890 | 891 | if (self.autoAdjustMenuWidth && ![self isContentViewHidden]) 892 | menuFrame.size.width = self.menuWidth; 893 | 894 | if (self.autoAdjustMenuWidth && self.slideDirection == NVSlideMenuControllerSlideFromRightToLeft && ![self isContentViewHidden]) 895 | menuFrame.origin.x = CGRectGetWidth(self.view.bounds) - self.menuWidth; 896 | 897 | return menuFrame; 898 | } 899 | 900 | 901 | - (UIViewAutoresizing)menuViewAutoresizingMaskAccordingToCurrentSlideDirection 902 | { 903 | UIViewAutoresizing resizingMask = UIViewAutoresizingFlexibleHeight; 904 | 905 | if (self.slideDirection == NVSlideMenuControllerSlideFromLeftToRight) 906 | resizingMask = resizingMask | UIViewAutoresizingFlexibleRightMargin; 907 | else 908 | resizingMask = resizingMask | UIViewAutoresizingFlexibleLeftMargin; 909 | 910 | return resizingMask; 911 | } 912 | 913 | @end 914 | 915 | 916 | #pragma mark - 917 | #pragma mark - UIViewController (NVSlideMenuController) 918 | 919 | @implementation UIViewController (NVSlideMenuController) 920 | 921 | - (NVSlideMenuController *)slideMenuController 922 | { 923 | NVSlideMenuController *slideMenuController = nil; 924 | UIViewController *parentViewController = self.parentViewController; 925 | 926 | while (!slideMenuController && parentViewController) 927 | { 928 | if ([parentViewController isKindOfClass:NVSlideMenuController.class]) 929 | slideMenuController = (NVSlideMenuController *) parentViewController; 930 | else 931 | parentViewController = parentViewController.parentViewController; 932 | } 933 | 934 | return slideMenuController; 935 | } 936 | 937 | @end 938 | 939 | #pragma mark - UIViewController (NVSlideMenuControllerCallbacks) 940 | 941 | @implementation UIViewController (NVSlideMenuControllerCallbacks) 942 | 943 | - (void)viewWillSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 944 | { 945 | // default implementation does nothing 946 | } 947 | 948 | 949 | - (void)viewDidSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 950 | { 951 | // default implementation does nothing 952 | } 953 | 954 | 955 | - (void)viewWillSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 956 | { 957 | // default implementation does nothing 958 | } 959 | 960 | 961 | - (void)viewDidSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 962 | { 963 | // default implementation does nothing 964 | } 965 | 966 | @end 967 | 968 | 969 | #pragma mark - 970 | #pragma mark - NVSlideMenuController (Deprecated) 971 | 972 | @implementation NVSlideMenuController (Deprecated) 973 | 974 | - (void)setContentViewWidthWhenMenuIsOpen:(CGFloat)contentViewWidthWhenMenuIsOpen 975 | { 976 | if (contentViewWidthWhenMenuIsOpen != _contentViewWidthWhenMenuIsOpen) 977 | { 978 | _contentViewWidthWhenMenuIsOpen = contentViewWidthWhenMenuIsOpen; 979 | if ([self isViewLoaded]) 980 | self.menuWidth = CGRectGetWidth(self.view.bounds) - _contentViewWidthWhenMenuIsOpen; 981 | } 982 | } 983 | 984 | 985 | - (CGFloat)contentViewWidthWhenMenuIsOpen 986 | { 987 | return _contentViewWidthWhenMenuIsOpen; 988 | } 989 | 990 | 991 | - (void)setPanEnabledWhenSlideMenuIsHidden:(BOOL)panEnabledWhenSlideMenuIsHidden 992 | { 993 | self.panGestureEnabled = panEnabledWhenSlideMenuIsHidden; 994 | } 995 | 996 | 997 | - (BOOL)panEnabledWhenSlideMenuIsHidden 998 | { 999 | return self.panGestureEnabled; 1000 | } 1001 | 1002 | 1003 | - (void)setContentViewController:(UIViewController *)contentViewController animated:(BOOL)animated completion:(void(^)(BOOL finished))completion 1004 | { 1005 | [self closeMenuBehindContentViewController:contentViewController animated:animated completion:completion]; 1006 | } 1007 | 1008 | 1009 | - (void)showContentViewControllerAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion 1010 | { 1011 | [self closeMenuAnimated:animated completion:completion]; 1012 | } 1013 | 1014 | 1015 | - (void)showMenuAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion 1016 | { 1017 | [self openMenuAnimated:animated completion:completion]; 1018 | } 1019 | 1020 | @end 1021 | 1022 | 1023 | 1024 | #pragma mark - 1025 | #pragma mark Private Categories 1026 | 1027 | #pragma mark UINavigationController (NVSlideMenuControllerCallbacks) 1028 | 1029 | @interface UINavigationController (NVSlideMenuControllerCallbacks) 1030 | // Forward callbacks to the topViewController 1031 | @end 1032 | 1033 | @implementation UINavigationController (NVSlideMenuControllerCallbacks) 1034 | 1035 | - (void)viewWillSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1036 | { 1037 | [self.topViewController viewWillSlideIn:animated inSlideMenuController:slideMenuController]; 1038 | } 1039 | 1040 | 1041 | - (void)viewDidSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1042 | { 1043 | [self.topViewController viewDidSlideIn:animated inSlideMenuController:slideMenuController]; 1044 | } 1045 | 1046 | 1047 | - (void)viewWillSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1048 | { 1049 | [self.topViewController viewWillSlideOut:animated inSlideMenuController:slideMenuController]; 1050 | } 1051 | 1052 | 1053 | - (void)viewDidSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1054 | { 1055 | [self.topViewController viewDidSlideOut:animated inSlideMenuController:slideMenuController]; 1056 | } 1057 | 1058 | @end 1059 | 1060 | 1061 | #pragma mark UISplitViewController (NVSlideMenuControllerCallbacks) 1062 | 1063 | @interface UISplitViewController (NVSlideMenuControllerCallbacks) 1064 | // Forward callbacks to the viewControllers 1065 | @end 1066 | 1067 | @implementation UISplitViewController (NVSlideMenuControllerCallbacks) 1068 | 1069 | - (void)viewWillSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1070 | { 1071 | [self.viewControllers enumerateObjectsUsingBlock:^(UIViewController *vc, NSUInteger idx, BOOL *stop) { 1072 | [vc viewWillSlideIn:animated inSlideMenuController:slideMenuController]; 1073 | }]; 1074 | } 1075 | 1076 | 1077 | - (void)viewDidSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1078 | { 1079 | [self.viewControllers enumerateObjectsUsingBlock:^(UIViewController *vc, NSUInteger idx, BOOL *stop) { 1080 | [vc viewDidSlideIn:animated inSlideMenuController:slideMenuController]; 1081 | }]; 1082 | } 1083 | 1084 | 1085 | - (void)viewWillSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1086 | { 1087 | [self.viewControllers enumerateObjectsUsingBlock:^(UIViewController *vc, NSUInteger idx, BOOL *stop) { 1088 | [vc viewWillSlideOut:animated inSlideMenuController:slideMenuController]; 1089 | }]; 1090 | } 1091 | 1092 | 1093 | - (void)viewDidSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1094 | { 1095 | [self.viewControllers enumerateObjectsUsingBlock:^(UIViewController *vc, NSUInteger idx, BOOL *stop) { 1096 | [vc viewDidSlideOut:animated inSlideMenuController:slideMenuController]; 1097 | }]; 1098 | } 1099 | 1100 | @end 1101 | 1102 | 1103 | #pragma mark UITabBarController (NVSlideMenuControllerCallbacks) 1104 | 1105 | @interface UITabBarController (NVSlideMenuControllerCallbacks) 1106 | // Forward callbacks to the selectedViewController 1107 | @end 1108 | 1109 | @implementation UITabBarController (NVSlideMenuControllerCallbacks) 1110 | 1111 | - (void)viewWillSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1112 | { 1113 | [self.selectedViewController viewWillSlideIn:animated inSlideMenuController:slideMenuController]; 1114 | } 1115 | 1116 | 1117 | - (void)viewDidSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1118 | { 1119 | [self.selectedViewController viewDidSlideIn:animated inSlideMenuController:slideMenuController]; 1120 | } 1121 | 1122 | 1123 | - (void)viewWillSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1124 | { 1125 | [self.selectedViewController viewWillSlideOut:animated inSlideMenuController:slideMenuController]; 1126 | } 1127 | 1128 | 1129 | - (void)viewDidSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1130 | { 1131 | [self.selectedViewController viewDidSlideOut:animated inSlideMenuController:slideMenuController]; 1132 | } 1133 | 1134 | @end 1135 | 1136 | 1137 | #pragma mark UIPageViewController (NVSlideMenuControllerCallbacks) 1138 | 1139 | @interface UIPageViewController (NVSlideMenuControllerCallbacks) 1140 | // Forward callbacks to the viewControllers 1141 | @end 1142 | 1143 | @implementation UIPageViewController (NVSlideMenuControllerCallbacks) 1144 | 1145 | - (void)viewWillSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1146 | { 1147 | [self.viewControllers enumerateObjectsUsingBlock:^(UIViewController *vc, NSUInteger idx, BOOL *stop) { 1148 | [vc viewWillSlideIn:animated inSlideMenuController:slideMenuController]; 1149 | }]; 1150 | } 1151 | 1152 | 1153 | - (void)viewDidSlideIn:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1154 | { 1155 | [self.viewControllers enumerateObjectsUsingBlock:^(UIViewController *vc, NSUInteger idx, BOOL *stop) { 1156 | [vc viewDidSlideIn:animated inSlideMenuController:slideMenuController]; 1157 | }]; 1158 | } 1159 | 1160 | 1161 | - (void)viewWillSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1162 | { 1163 | [self.viewControllers enumerateObjectsUsingBlock:^(UIViewController *vc, NSUInteger idx, BOOL *stop) { 1164 | [vc viewWillSlideOut:animated inSlideMenuController:slideMenuController]; 1165 | }]; 1166 | } 1167 | 1168 | 1169 | - (void)viewDidSlideOut:(BOOL)animated inSlideMenuController:(NVSlideMenuController *)slideMenuController 1170 | { 1171 | [self.viewControllers enumerateObjectsUsingBlock:^(UIViewController *vc, NSUInteger idx, BOOL *stop) { 1172 | [vc viewDidSlideOut:animated inSlideMenuController:slideMenuController]; 1173 | }]; 1174 | } 1175 | 1176 | @end 1177 | --------------------------------------------------------------------------------