Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
andreamazz committed Aug 14, 2012
1 parent f183fed commit 62aad6f
Show file tree
Hide file tree
Showing 35 changed files with 2,103 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# OsX
.DS_Store
# Xcode
build/*
*.pbxuser
Expand Down
54 changes: 54 additions & 0 deletions AMSlideOut/AMSlideOutGlobals.h
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]
47 changes: 47 additions & 0 deletions AMSlideOut/AMSlideOutNavigationController.h
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
289 changes: 289 additions & 0 deletions AMSlideOut/AMSlideOutNavigationController.m
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
Loading

0 comments on commit 62aad6f

Please sign in to comment.