forked from andreamazz/SlideOutNavigation
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f183fed
commit 62aad6f
Showing
35 changed files
with
2,103 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
# OsX | ||
.DS_Store | ||
# Xcode | ||
build/* | ||
*.pbxuser | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// | ||
// AMSlideOutGlobals.h | ||
// SlideOut | ||
// | ||
// Created by Andrea on 14/08/12. | ||
// Copyright (c) 2012 Andrea Mazzini. All rights reserved. | ||
// | ||
// 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: | ||
// | ||
// The above copyright notice and this permission notice shall be included | ||
// in all copies or substantial portions of the Software. | ||
// | ||
// 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. | ||
|
||
#define kSOViewTitle @"title" | ||
#define kSOController @"controller" | ||
#define kSOViewIcon @"icon" | ||
#define kSOSection @"section" | ||
#define kSOSectionTitle @"title" | ||
|
||
// SlideOut Controller | ||
#define kSlideValue 260 | ||
#define kBackground [UIColor colorWithRed:0.19 green:0.22 blue:0.29 alpha:1.0] | ||
#define kSelectionBackground [UIColor colorWithRed:0.10 green:0.13 blue:0.20 alpha:1.0] | ||
|
||
// Table Cell | ||
#define kImagePadding 50 | ||
#define kTextPadding 20 | ||
#define kCellBackground [UIColor colorWithRed:0.19 green:0.22 blue:0.29 alpha:1.0].CGColor | ||
#define kUpperSeparator [UIColor colorWithRed:0.24 green:0.27 blue:0.33 alpha:1.0].CGColor | ||
#define kLowerSeparator [UIColor colorWithRed:0.14 green:0.16 blue:0.21 alpha:1.0].CGColor | ||
#define kCellFontColor [UIColor colorWithRed:0.77 green:0.8 blue:0.85 alpha:1.0] | ||
#define kCellShadowColor [UIColor colorWithRed:0.21 green:0.15 blue:0.19 alpha:1.0] | ||
|
||
// Header Cell | ||
#define kTextHeaderPadding 10 | ||
#define kGradientUp [UIColor colorWithRed:0.26 green:0.29 blue:0.36 alpha:1] | ||
#define kGradientDown [UIColor colorWithRed:0.22 green:0.25 blue:0.32 alpha:1] | ||
#define kUpperSeparator [UIColor colorWithRed:0.24 green:0.27 blue:0.33 alpha:1.0].CGColor | ||
#define kLowerSeparator [UIColor colorWithRed:0.14 green:0.16 blue:0.21 alpha:1.0].CGColor | ||
#define kFontColor [UIColor colorWithRed:0.49 green:0.50 blue:0.57 alpha:1.0] | ||
#define kFontShadowColor [UIColor colorWithRed:0.21 green:0.15 blue:0.19 alpha:1.0] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// | ||
// AMSlideOutNavigationController.h | ||
// SlideOut | ||
// | ||
// Created by Andrea on 12/08/12. | ||
// Copyright (c) 2012 Andrea Mazzini. All rights reserved. | ||
// | ||
// 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: | ||
// | ||
// The above copyright notice and this permission notice shall be included | ||
// in all copies or substantial portions of the Software. | ||
// | ||
// 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. | ||
|
||
#import <UIKit/UIKit.h> | ||
#import <QuartzCore/QuartzCore.h> | ||
#import "AMSlideOutGlobals.h" | ||
|
||
@interface AMSlideOutNavigationController : UIViewController <UITableViewDataSource, UITableViewDelegate, UIGestureRecognizerDelegate> | ||
{ | ||
BOOL _menuVisible; | ||
__strong UIView* _overlayView; | ||
__strong UIBarButtonItem* _barButton; | ||
__strong UITapGestureRecognizer* _tapGesture; | ||
__strong UIPanGestureRecognizer* _panGesture; | ||
} | ||
|
||
@property (strong, nonatomic) NSMutableArray* menuItems; | ||
@property (strong, nonatomic) UINavigationController* contentController; | ||
@property (strong, nonatomic) UITableView* tableView; | ||
|
||
+ (id)slideOutNavigationWithMenuItems:(NSArray*)items; | ||
- (id)initWithMenuItems:(NSArray*)items; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,289 @@ | ||
// | ||
// AMSlideOutNavigationController.m | ||
// SlideOut | ||
// | ||
// Created by Andrea on 12/08/12. | ||
// Copyright (c) 2012 Andrea Mazzini. All rights reserved. | ||
// | ||
|
||
#import "AMSlideOutNavigationController.h" | ||
#import "AMSlideTableCell.h" | ||
#import "AMSlideTableHeader.h" | ||
|
||
@interface AMSlideOutNavigationController () | ||
|
||
@end | ||
|
||
@implementation AMSlideOutNavigationController | ||
|
||
@synthesize contentController = _contentController; | ||
@synthesize tableView = _tableView; | ||
@synthesize menuItems = _menuItems; | ||
|
||
- (id)initWithMenuItems:(NSArray*)items | ||
{ | ||
self = [super init]; | ||
if (self) { | ||
_menuVisible = NO; | ||
self.menuItems = [NSMutableArray arrayWithArray:items]; | ||
} | ||
return self; | ||
} | ||
|
||
+ (id)slideOutNavigationWithMenuItems:(NSArray*)items | ||
{ | ||
return [[AMSlideOutNavigationController alloc] initWithMenuItems:items]; | ||
} | ||
|
||
- (void)setContentViewController:(UIViewController *)controller | ||
{ | ||
// Sets the view controller as the new root view controller for the navigation controller | ||
[self.contentController setViewControllers:[NSArray arrayWithObject:controller] animated:NO]; | ||
[self.contentController.topViewController.navigationItem setLeftBarButtonItem:_barButton]; | ||
} | ||
|
||
- (void)loadView | ||
{ | ||
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; | ||
[view setBackgroundColor:kBackground]; | ||
|
||
// Table View setup | ||
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)]; | ||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; | ||
self.tableView.backgroundColor = kBackground; | ||
|
||
// The content is displayed in a UINavigationController | ||
self.contentController = [[UINavigationController alloc] init]; | ||
self.contentController.view.layer.shadowColor = [UIColor blackColor].CGColor; | ||
self.contentController.view.layer.shadowOffset = CGSizeMake(-10, 0); | ||
self.contentController.view.layer.shadowOpacity = 0.4; | ||
self.contentController.view.layer.shadowRadius = 10.0; | ||
self.contentController.view.clipsToBounds = NO; | ||
|
||
/* The transparent overlay view will catch all the user touches in the content area | ||
when the slide menu is visible */ | ||
_overlayView = [[UIView alloc] initWithFrame:self.contentController.view.frame]; | ||
_overlayView.userInteractionEnabled = YES; | ||
_overlayView.backgroundColor = [UIColor clearColor]; | ||
|
||
[view addSubview:self.tableView]; | ||
[view addSubview:self.contentController.view]; | ||
|
||
self.view = view; | ||
} | ||
|
||
- (void)viewDidLoad | ||
{ | ||
[super viewDidLoad]; | ||
|
||
[self.tableView setDelegate:self]; | ||
[self.tableView setDataSource:self]; | ||
|
||
_barButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"iconSlide.png"] | ||
style:UIBarButtonItemStylePlain | ||
target:self | ||
action:@selector(toggleMenu)]; | ||
|
||
// Detect when the content recieves a single tap | ||
_tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; | ||
[_overlayView addGestureRecognizer:_tapGesture]; | ||
|
||
// Detect when the content is touched and dragged | ||
_panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; | ||
[_panGesture setMaximumNumberOfTouches:2]; | ||
[_panGesture setDelegate:self]; | ||
[_overlayView addGestureRecognizer:_panGesture]; | ||
|
||
// Select the first view controller | ||
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionTop]; | ||
[self tableView:self.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; | ||
} | ||
|
||
- (void)setMenuItems:(NSArray *)menuItems | ||
{ | ||
// Makes sure to refresh the table data when new items are set | ||
_menuItems = [NSMutableArray arrayWithArray:menuItems]; | ||
[self.tableView reloadData]; | ||
} | ||
|
||
#pragma mark Table View delegates | ||
|
||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView | ||
{ | ||
return [self.menuItems count]; | ||
} | ||
|
||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section | ||
{ | ||
return [[[self.menuItems objectAtIndex:section] objectForKey:kSOSection] count]; | ||
} | ||
|
||
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section | ||
{ | ||
return [[self.menuItems objectAtIndex:section] objectForKey:kSOSectionTitle]; | ||
} | ||
|
||
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath | ||
{ | ||
static NSString* cellID = @"AMSlideTableCell"; | ||
|
||
NSDictionary* dict = [[[self.menuItems objectAtIndex:indexPath.section] objectForKey:kSOSection] objectAtIndex:indexPath.row]; | ||
UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:cellID]; | ||
if (cell == nil) { | ||
cell = [[AMSlideTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CellID"]; | ||
} | ||
|
||
cell.textLabel.text = [dict objectForKey:kSOViewTitle]; | ||
UIView* selection = [[UIView alloc] initWithFrame:cell.frame]; | ||
[selection setBackgroundColor:kSelectionBackground]; | ||
cell.selectedBackgroundView = selection; | ||
|
||
NSString* image = [dict objectForKey:kSOViewIcon]; | ||
if (image != nil && ![image isEqualToString:@""]) { | ||
cell.imageView.image = [UIImage imageNamed:image]; | ||
} else { | ||
cell.imageView.image = nil; | ||
} | ||
|
||
return cell; | ||
} | ||
|
||
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section | ||
{ | ||
AMSlideTableHeader *header = [[AMSlideTableHeader alloc] init]; | ||
header.titleLabel.text = [self tableView:tableView titleForHeaderInSection:section]; | ||
return header; | ||
} | ||
|
||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section | ||
{ | ||
return 22; | ||
} | ||
|
||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath | ||
{ | ||
return 44; | ||
} | ||
|
||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath | ||
{ | ||
NSDictionary* dict = [[[self.menuItems objectAtIndex:indexPath.section] objectForKey:kSOSection] objectAtIndex:indexPath.row]; | ||
|
||
[self setContentViewController:[dict objectForKey:kSOController]]; | ||
[self hideSideMenu]; | ||
} | ||
|
||
- (void)toggleMenu | ||
{ | ||
if (_menuVisible) { | ||
[self hideSideMenu]; | ||
} else { | ||
[self showSideMenu]; | ||
} | ||
} | ||
|
||
- (void)showSideMenu | ||
{ | ||
[UIView animateWithDuration:0.15 | ||
delay:0 | ||
options:UIViewAnimationOptionCurveEaseInOut | ||
animations:^{ | ||
// Move the whole NavigationController view aside | ||
CGRect frame = self.contentController.view.frame; | ||
frame.origin.x = kSlideValue; | ||
self.contentController.view.frame = frame; | ||
} | ||
completion:^(BOOL finished) { | ||
// Add the overlay that will receive the gestures | ||
[self.contentController.topViewController.view addSubview:_overlayView]; | ||
_menuVisible = YES; | ||
[_barButton setStyle:UIBarButtonItemStyleDone]; | ||
}]; | ||
|
||
} | ||
|
||
- (void)hideSideMenu | ||
{ | ||
// this animates the screenshot back to the left before telling the app delegate to swap out the MenuViewController | ||
// it tells the app delegate using the completion block of the animation | ||
[UIView animateWithDuration:0.15 | ||
delay:0 | ||
options:UIViewAnimationOptionCurveEaseInOut | ||
animations:^{ | ||
// Move back the NavigationController | ||
CGRect frame = self.contentController.view.frame; | ||
frame.origin.x = 0; | ||
self.contentController.view.frame = frame; | ||
} | ||
completion:^(BOOL finished) { | ||
[_overlayView removeFromSuperview]; | ||
_menuVisible = NO; | ||
[_barButton setStyle:UIBarButtonItemStylePlain]; | ||
}]; | ||
} | ||
|
||
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer | ||
{ | ||
// A single tap hides the slide menu | ||
[self hideSideMenu]; | ||
} | ||
|
||
/* The following is from | ||
http://blog.shoguniphicus.com/2011/06/15/working-with-uigesturerecognizers-uipangesturerecognizer-uipinchgesturerecognizer/ | ||
as mentioned by Nick Harris, in his approach to slide-out navigation: | ||
http://nickharris.wordpress.com/2012/02/05/ios-slide-out-navigation-code/ | ||
*/ | ||
- (void)handlePan:(UIPanGestureRecognizer *)gesture; | ||
{ | ||
// The pan gesture moves horizontally the view | ||
UIView *piece = self.contentController.view; | ||
[self adjustAnchorPointForGestureRecognizer:gesture]; | ||
|
||
if ([gesture state] == UIGestureRecognizerStateBegan || [gesture state] == UIGestureRecognizerStateChanged) { | ||
|
||
CGPoint translation = [gesture translationInView:[piece superview]]; | ||
|
||
[piece setCenter:CGPointMake([piece center].x + translation.x, [piece center].y)]; | ||
[gesture setTranslation:CGPointZero inView:[piece superview]]; | ||
} | ||
else if ([gesture state] == UIGestureRecognizerStateEnded) { | ||
// Hide the slide menu only if the view is released under a certain threshold | ||
if (self.contentController.view.frame.origin.x < kSlideValue) { | ||
[self hideSideMenu]; | ||
} else { | ||
[self showSideMenu]; | ||
} | ||
} | ||
} | ||
|
||
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer | ||
{ | ||
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { | ||
UIView *piece = self.contentController.view; | ||
CGPoint locationInView = [gestureRecognizer locationInView:piece]; | ||
CGPoint locationInSuperview = [gestureRecognizer locationInView:piece.superview]; | ||
|
||
piece.layer.anchorPoint = CGPointMake(locationInView.x / piece.bounds.size.width, locationInView.y / piece.bounds.size.height); | ||
piece.center = locationInSuperview; | ||
} | ||
} | ||
|
||
- (void)viewDidUnload | ||
{ | ||
[super viewDidUnload]; | ||
[self setTableView:nil]; | ||
[self setContentController:nil]; | ||
[_overlayView removeGestureRecognizer:_tapGesture]; | ||
[_overlayView removeGestureRecognizer:_panGesture]; | ||
_tapGesture = nil; | ||
_panGesture = nil; | ||
_overlayView = nil; | ||
_barButton = nil; | ||
} | ||
|
||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation | ||
{ | ||
return (interfaceOrientation == UIInterfaceOrientationPortrait); | ||
} | ||
|
||
@end |
Oops, something went wrong.