Update: March 2, 2015

This tutorial was written in early 2013 for iOS 6 with autolayout disabled. It is far outdated at this point, and I wouldn’t recommend following it. It uses version 1 of ECSlidingViewController, which is now at a completely changed version 2.

I don’t have a good recommendation for what library to use now because I have not tried many lately. However, I would actually recommend avoiding the sliding view / hamburger menu if at all possible. There have been many good articles written in the past year or two with research on why hamburger menus are bad, and how to rethink your interface to avoid them.

If you’re interested in why I no longer support hamburger menus, check out some of these posts:



A lot of the big apps have started using a cool new interface design that is both highly usable and feels slick and natural. There are a lot of different ways to implement this type of functionality. The way I’ve chosen, and will demonstrate here, is an open source library called ECSlidingViewController.

In this tutorial we will create a simple to-do app that features this slide-out navigation. The main screen will have a list of to-do items, and if we swipe to the right we reveal a menu with a list of categories for our to-do items underneath the left side.

As with most of my tutorials, I expect at least a basic level of Objective-C and iOS understanding as a prerequisite. I write in the style of Modern Objective-C, which means things like not synthesizing properties or forward declaring methods. Also, for this tutorial I will disable auto-layout. This project was written in Xcode 4.6.1 targeting iOS 6.1. However, it will work with iOS 5.0, and should be fine at least back to Xcode 4.5 or 4.2.

Getting Started

Start by creating a new Xcode project with the Single View Application template. Use storyboards and ARC. Storyboards are not required for ECSlidingViewController, but I will be using them in this tutorial.

Next, you will need to include the ECSlidingViewController source code from GitHub. Clone the project, or download the zip. The files we are looking for are in ECSlidingViewController/Vendor/ECSlidingViewController. Grab the four files in this directory and add them to your project in Xcode. I prefer to grab the whole Vendor folder to keep things organized in my project.

We also need to include the QuartzCore.framework. Select the root of your project in Xcode, then your Target, and the Summary tab. Click the + button under Linked Frameworks and Libraries. Find the QuartzCore.framework and click Add.

Setting up the Main View

We can delete the view that was created for us, as well as ViewController.h and ViewController.m. We will start by creating the InitialSlidingViewController which acts as a sort of container or controller of the sliding views. Add a new Objective-C class file to your project. Give it the name InitialSlidingViewController, and set it as a subclass of ECSlidingViewController.

You can remove the boiler plate methods it creates in the .m file if you want. Leave the viewDidLoad method though as we will be using it later.

Now go back to the storyboard and drag out a new View Controller. In the Identity Inspector set the class to InitialSlidingViewController. Make sure the view has the arrow next to it indicating that it is the Initial View Controller. If not, open the Attributes Inspector and check the box for “Is Initial View Controller”.

At this point you can build and run to make sure everything compiles correctly. You should see an exciting blank white screen after it launches.

We can now add the top view controller where our to-do list will sit. Add another new Objective-C class file called ToDoViewController as a subclass of UIViewController. Again you should delete the boiler plate methods other than viewDidLoad.

Back on the storyboard, drag out another UIViewController and set the class to ToDoViewController. Now another important step is to set the Storyboard ID located just below the Class in the Identity Inspector. Set it to ToDoView. You might want to temporarily change the background color, so when you build and run in a bit you know you are seeing this view.

Go to the InitialSlidingViewController.m file and replace the viewDidLoad method with the following code.

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"ToDoView"];
}

This will create a new instance of ToDoViewController and set it as the topViewController. If you build and run now you should get a blank background of whatever color you chose.

Let’s Start Sliding Already!

We are now ready to add the “Under Left” controller and enable sliding of the top view. First of all, we need to add the following imports to the top of ToDoViewController.m.

#import <QuartzCore/QuartzCore.h>
#import "ECSlidingViewController.h"

Now we can add another Objective-C class file for the view controller that will be underneath on the left side. We can call this MenuViewController, and subclass UIViewController. Replace the contents of MenuViewController.m with the following.

#import "MenuViewController.h"
#import "ECSlidingViewController.h"

@implementation MenuViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.slidingViewController setAnchorRightRevealAmount:280.0f];
    self.slidingViewController.underLeftWidthLayout = ECFullWidth;
}

@end

The anchor right reveal amount is how much of the under left controller should be visible when the top view is anchored to the right edge. If you rotate, the width of the under left will stay the same, but the amount that the top view shows will vary. They provide a method “setAnchorRightPeekAmount” if you want to set the top view to always be showing a specified amount instead.

Let’s jump back to the storyboard and drag out another UIViewController. Give it a Storyboard ID of MenuView, and don’t forget to set the class to MenuViewController. Change the background to something different, so when we run in a few you know you are seeing it.

Now jump back to the ToDoViewController.m, so we can tell it what view we want under left. Import the MenuViewController.h and add a viewWillAppear method as follows:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // Add a shadow to the top view so it looks like it is on top of the others
    self.view.layer.shadowOpacity = 0.75f;
    self.view.layer.shadowRadius = 10.0f;
    self.view.layer.shadowColor = [[UIColor blackColor] CGColor];

    // Tell it which view should be created under left
    if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
        self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"MenuView"];
    }

    // Add the pan gesture to allow sliding
    [self.view addGestureRecognizer:self.slidingViewController.panGesture];
}

First we added a shadow, so it appears to be on top of the under left view. Then we check to see if we already created the underLeftViewController. If not, we instantiate a new one from the storyboard and set it as the property of our slidingViewController. Finally, we added the panGesture that is defined for us to our view.

You should build and run at this point, and you should be able to drag the top view to the right edge.

Build out the To-Do Tables

I want to cover how to pass information back and forth between the top and underneath controllers. Before I can do that though we need to be displaying some data. Since this tutorial is focused on creating the sliding navigation, I’m not going to go into detail with these steps. I will just list the steps along with the code. You should be comfortable with quickly creating table views since they are such a staple of iOS development.

ToDoViewController on Storyboard

  1. Add a Navigation Bar
  2. Add a table view in remaining area
  3. Drag from table view to ToDoViewController and set it as delegate and dataSource.
  4. Add a prototype cell with Identifier “Cell”.

ToDoViewController.m changes

In a real app, you would have some kind of data store for the to do list, but in this case I will just be creating a hard coded sample list in viewDidLoad.

Replace the contents of ToDoViewController.m with the following:

#import "ToDoViewController.h"
#import <QuartzCore/QuartzCore.h>
#import "ECSlidingViewController.h"
#import "MenuViewController.h"

@interface ToDoViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, weak) IBOutlet UINavigationItem *navigationTitle;
@property (nonatomic, strong) NSArray *toDoCategories;
@property (nonatomic, assign) NSInteger selectedCategory;
@end

@implementation ToDoViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSDictionary *choresDictionary = @{@"title": @"Chores",
                                       @"items": @[@"Sweep", @"Dishes", @"Mow the lawn"]};
    NSDictionary *workDictionary = @{@"title": @"Work",
                                     @"items": @[@"TPS Report"]};
    NSDictionary *groceryDictionary = @{@"title": @"Grocery List",
                                        @"items": @[@"Chips", @"Salsa", @"Fruit snacks", @"Beer"]};

    self.toDoCategories = @[choresDictionary, workDictionary, groceryDictionary];
    self.selectedCategory = 0;
    self.navigationTitle.title = self.toDoCategories[self.selectedCategory][@"title"];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // Add a shadow to the top view so it looks like it is on top of the others
    self.view.layer.shadowOpacity = 0.75f;
    self.view.layer.shadowRadius = 10.0f;
    self.view.layer.shadowColor = [[UIColor blackColor] CGColor];

    // Tell it which view should be created under left
    if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
        self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"MenuView"];
    }

    // Add the pan gesture to allow sliding
    [self.view addGestureRecognizer:self.slidingViewController.panGesture];
}

#pragma mark - Tableview DataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSDictionary *currentCategory = self.toDoCategories[self.selectedCategory];
    return [currentCategory[@"items"] count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    NSDictionary *currentCategory = self.toDoCategories[self.selectedCategory];
    cell.textLabel.text = currentCategory[@"items"][indexPath.row];

    return cell;
}

@end

Go back to the Storyboard and connect the “navigationTitle” outlet to the Navigation Item (Title) in the Navigation bar in our ToDoViewController.

If you build and run now, you should have something similar to this.

Next we need to get the MenuViewController ready, then we can start passing information between the views.

  1. Add a Navigation Bar with title Category
  2. Add a UITableView
  3. Set delegate and dataSource
  4. Add prototype cell as Cell.

Replace MenuViewController.h content with:

@interface MenuViewController : UIViewController
@property (nonatomic, strong) NSArray *categoryList;
@end

Replace MenuViewController.m with:

#import "MenuViewController.h"
#import "ECSlidingViewController.h"

@interface MenuViewController() <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, weak) IBOutlet UINavigationBar *navigationBar;
@end

@implementation MenuViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.slidingViewController setAnchorRightRevealAmount:280.0f];
    self.slidingViewController.underLeftWidthLayout = ECFullWidth;

    self.categoryList = @[];
}

#pragma mark - Tableview DataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.categoryList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    NSDictionary *currentCategory = self.categoryList[indexPath.row];
    cell.textLabel.text = currentCategory[@"title"];

    return cell;
}

@end

At this point we need to pass a list of categories from our to-do view to the menu view in order to populate the table. In a real app this would likely come from a database, but I don’t want to focus on that kind of stuff for this example. Back in the ToDoViewController.m we need to add the following line of code right below where we instantiate the MenuView, inside the if block, inside viewWillAppear.

[(MenuViewController *)self.slidingViewController.underLeftViewController setCategoryList:self.toDoCategories];

You can build and run at this point and you should have a list of categories now.

Passing Data

At this point our interface is complete. You can grab a copy of the code up to this point by checking out the tag “CompleteInterface” from the GitHub project. I’m going to cover how I like to pass data between the underneath view and the top view.

My preferred method is to use the Delegate-Protocol paradigm. I have also used a technique where I override the setter on the top view for whatever property holds the data, and set that from the underneath view. I’ll talk more about why and how to use that at the end of this section, but for now we will use the Delegate-Protocol because that fits best for this situation.

We are going to make the top view controller a delegate for the menu view, and when a category is selected in the menu we will call a delegate method telling the top view what happened.

Replace the code in MenuViewController.h with the following:

#import <UIKit/UIKit.h>

@protocol MenuViewControllerDelegate;

@interface MenuViewController : UIViewController
@property (nonatomic, weak) id <MenuViewControllerDelegate> delegate;
@property (nonatomic, strong) NSArray *categoryList;
@end

@protocol MenuViewControllerDelegate
-(void)menuViewControllerDidFinishWithCategoryId:(NSInteger)categoryId;
@end

This gives the protocol definition, saying that whoever wants to be a delegate for this class must implement these methods.

Now in MenuViewController.m add the following method below cellForRowAtIndexPath.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self.delegate menuViewControllerDidFinishWithCategoryId:indexPath.row];
}

All this does is when a cell is selected it tells it’s delegate which spot in the array it was. We are done with the MenuViewController now and can finish up the ToDoViewController.

In ToDoViewController.m we need to tell the compiler that we will conform to the MenuViewControllerDelegate. At the top of the file, add it to the list of delegates.

@interface ToDoViewController () <UITableViewDataSource, UITableViewDelegate, MenuViewControllerDelegate>

Below the line in viewDidAppear where you set the categoryList on the MenuViewController instance, add a line to set the delegate.

[(MenuViewController *)self.slidingViewController.underLeftViewController setDelegate:self];

Finally, we just have to implement the method we said we would for when the menu controller finishes. Add the delegate method below the cellForRowAtIndexPath method.

- (void)menuViewControllerDidFinishWithCategoryId:(NSInteger)categoryId
{
    self.selectedCategory = categoryId;
    self.navigationTitle.title = self.toDoCategories[self.selectedCategory][@"title"];
    [self.tableView reloadData];
    [self.slidingViewController resetTopView];
}

What we are doing here is setting the category id that was returned to us to our property that keeps track of this. Then we change the the title to the new category. For our changes to take place we need to reload the data on the table view. Then we can tell our slidingViewController to return us back to the top view.

Before we can build and run though we need a property for the tableView. Add the following property to the top of the file with all the other properties.

@property (nonatomic, weak) IBOutlet UITableView *tableView;

Then switch to the Storyboard and connect the UITableView to this property.

When you build and run this time you should be able to select a different category and it should automatically slide back over and replace the items in the list with those in the selected category. That’s it, you have a functioning app with a slide-out navigation.

Didn’t you mention something about a setter?

Imagine a scenario where the menu can drill down multiple times before selecting something that should return it to the top. For instance, you select “Chores”, which then drills you down another level with options for “House” or “Lawn”. Then when you select one of those it brings you back to the to-do list.

In this case we now have a UINavigationController, and two view controllers in our hierarchy before we want to go back to the top. We don’t want to start passing the delegate all over the place. With ECSlidingViewController we can always find the top view with self.slidingViewController.topViewController. So, if we create a public property for selectedCategory in our ToDoViewController.h we can set it from any level of our hierarchy. Then in the implementation file we would override the setter to do things like change the title and reload the data in the table view.

Where to go from here

You can download the completed code on my GitHub here if you had any problems. Obviously this app is far from complete since you can’t add/remove tasks or categories. You could implement that functionality, or find something to put as the underRightViewController and allow panning in either direction.