How to Create a Slide-Out Navigation Panel

Tammy Coron
Facebook Slide

Slide to the right!

Update 10/14/14: This tutorial has now been updated for iOS 8 and Swift; check it out!

This tutorial will show you how to build a slide-out navigation mechanism similar to the ones available in the Facebook and Path iOS apps.

The slide-out design pattern lets developers add permanent navigation to their apps without taking up valuable screen real estate. The user can choose to reveal the navigation at any time, while still seeing their current context.

These days, there are many pre-built solutions out there you can use, such as John-Lluch’s excellent SWRevealViewController. If you’re looking for the quickest and easiest way, using that library might be a good way to go.

However, if you’re a DIY kind of programmer (like me), you might want to understand how you can implement this yourself.

In this tutorial, you’ll see that it’s really not as complicated as you might think. You’ll take a less-is-more approach and skip all of the complicated code that’s not really required, so that you can apply the slide-out navigation technique to your own applications with relative ease.

So sit back, grab a Mac, and get ready to learn how to do the Slide-Out, complete with hand gestures! Boogie-woogie-woogie!

Getting Started

So what exactly is this slide-out feature you’ll be creating?

iOS designer and developer Ken Yarmosh explains it best: “Slide-out navigation consists of a panel that ‘slides out’ from underneath the left or the right of the main content area, revealing a vertically independent scroll view that serves as the primary navigation for the application.”

Note: For an in-depth look (and pretty pictures), check out Ken’s post New iOS Design Pattern: Slide-Out Navigation. He does a great job of explaining the benefits of using this design pattern and showing common uses in the wild.

To get started, download the starter project for this tutorial. It’s a ZIP file, so save it to a convenient location and then extract it to get the project.

Next open the project in Xcode and take a look at how it’s organized.

The project is grouped into three main folders:

  • Assets: All of the images and other non-code assets like the attribution file.
  • Views: The main interface builder files for this project.
  • Classes: The actual Objective-C code files.

Project Layout

Don’t worry too much about the Assets group. You won’t be making any changes to it. All of the necessary resources have already been added for you.

Take a look at the Views folder and notice there are four main view controllers. When it comes time to adapt this tutorial to your own projects, here’s what you should keep in mind:

  • MainViewController: This is where the magic happens! The one you need to add to your own projects (with some minor modifications).
  • CenterViewController: The center panel. This can be replaced with your own view controller (make sure you copy the button actions).
  • LeftPanelViewController: The left panel. This can be replaced with your own view controller.
  • RightPanelViewController: The right panel. This can be replaced with your own view controller.

Now head over to the AppDelegate.m file. Although you won’t be making any changes here either, you should be aware that MainViewController is your “container” for the left, center and right view controllers. The allocation of the controller happens on line 19:

self.viewController = [[MainViewController alloc] initWithNibName:@"MainViewController" bundle:nil];

Now that you’re familiar with the pattern of the project, it’s time to get your balance and start at square one: the center panel.

Finding Your Center

In this section, you are going to place the CenterViewController inside the MainViewController, as a child view controller.

Note: This section uses a concept called View Controller Containment introduced in iOS 5. If you are new to this concept, check out Chapter 22 in iOS 5 by Tutorials, “UIViewController Containment.”

Open MainViewController.m and add the following import statement at the top of the file:

#import "CenterViewController.h"

Right below that, add a constant definition:

#define CENTER_TAG 1

Next add the following property within the @interface section to make it easier to get a handle on your center view:

@property (nonatomic, strong) CenterViewController *centerViewController;

Find setupView and add the following block of code to it:

self.centerViewController = [[CenterViewController alloc] initWithNibName:@"CenterViewController" bundle:nil];
self.centerViewController.view.tag = CENTER_TAG;
self.centerViewController.delegate = self;
[self.view addSubview:self.centerViewController.view];
[self addChildViewController:_centerViewController];
[_centerViewController didMoveToParentViewController:self];

The code above allocates a new CenterViewController and assigns it to the property centerViewController. It then sets the tag for the view controller’s view to CENTER_TAG.

The next thing the code does is set the delegate to MainViewController. This means you need to modify the interface of this class so that it will adhere to the protocol requirements of CenterViewControllerDelegate. Do this by adding the following line to the end of the @interface line at the top:


The finished line should look like this:

@interface MainViewController () <CenterViewControllerDelegate>

Finally, the code above adds centerViewController’s view to MainViewController’s view using addSubview:, addChildViewContoller: and didMoveToParentViewController:.

Now is a good time to check your progress. Build and run the project. If all went well, you should see something similar to the screen below:

Main Screen

Yes, those buttons at the top will bring you kitties and puppies. What better reason could there be for creating sliding navigation panels? But to get your cuteness fix, you’ve got to start sliding. First, to the left!

Lean to the Left…

You’ve created your center panel, but adding the left view controller requires a different set of steps.

Return to MainViewController.m and add the following import statement at the top of the file:

#import "LeftPanelViewController.h"

Right below that line, add another definition:

#define LEFT_PANEL_TAG 2

Next add the following properties within the @interface section, similar to what you did for the center view:

@property (nonatomic, strong) LeftPanelViewController *leftPanelViewController;
@property (nonatomic, assign) BOOL showingLeftPanel;

Now locate getLeftView, remove the existing code and add the following:

// init view if it doesn't already exist
if (_leftPanelViewController == nil)	
	// this is where you define the view for the left panel
	self.leftPanelViewController = [[LeftPanelViewController alloc] initWithNibName:@"LeftPanelViewController" bundle:nil];
	self.leftPanelViewController.view.tag = LEFT_PANEL_TAG;
	self.leftPanelViewController.delegate = _centerViewController;
	[self.view addSubview:self.leftPanelViewController.view];
	[self addChildViewController:_leftPanelViewController];
	[_leftPanelViewController didMoveToParentViewController:self];
	_leftPanelViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
self.showingLeftPanel = YES;
// set up view shadows
[self showCenterViewWithShadow:YES withOffset:-2];
UIView *view = self.leftPanelViewController.view;
return view;

The code above first checks to see if the leftPanelViewController property is nil. If it is, the code allocates, initializes and assigns a new LeftPanelViewController controller to the leftPanelViewController property.

Next the code assigns a tag and a delegate – used for image selection – and the newly created view is added to the main view.

The code then sets a value of YES for the showingLeftPanel property and adds a little visual treatment, explained in the next section.

Finally the code returns the view to the calling function. As for why it does that – you’ll see in the section after the next.


Next you’ll take a little detour into the shadows.

Don’t Forget Your Shadow

Within the block of code you just added, you may have noticed a call to showCenterViewWithShow:withOffset:. This method, which you are about to add, creates a shadow effect using the QuartzCore framework.

In order to have access to the many wonderful features in this framework, add the following import statement at the top of MainViewController.m:

#import <QuartzCore/QuartzCore.h>

Also, add a definition for the corner radius at the top of the file. That way, if you ever want to change the corner radius, you’ll only have to modify it in one place.


Now locate the showCenterViewWithShadow:withOffset: method and add the following block of code to it:

if (value)
	[_centerViewController.view.layer setCornerRadius:CORNER_RADIUS];
	[_centerViewController.view.layer setShadowColor:[UIColor blackColor].CGColor];
	[_centerViewController.view.layer setShadowOpacity:0.8];
	[_centerViewController.view.layer setShadowOffset:CGSizeMake(offset, offset)];
	[_centerViewController.view.layer setCornerRadius:0.0f];
	[_centerViewController.view.layer setShadowOffset:CGSizeMake(offset, offset)];

What does the above do, you ask? It sets rounded corners and a drop shadow to the center view if a non-zero value is passed to the method. Otherwise, the rounded corners are set back to non-rounded.

Of course, you won’t see these effects yet if you build and run, since this particular bit of code is not in use yet. All in good time! :]


Now Back to the Left

Now that you’ve got the goods to dress up your sliding panel, finish off your left view controller. Once you’ve done so, you’ll know how to execute the same moves on the right side.

In the interests of keeping this tutorial focused on the important stuff, the IBActions and IBOutlets have been pre-connected for you in the interface builder files. However, to implement your DIY slide-out navigation, you need to understand how the buttons are configured.

Take a look at this screenshot of the CenterViewController.xib file and notice the connections:

Left Button Setup - Xcode

The kitties button, which is hooked up to an IBOutlet named leftButton, has its Touch Up Inside event connected to an IBAction named btnMovePanelRight:. This button controls the sliding of the center panel to reveal the left-side panel.

The method is currently empty, and it’s time for you to fill it.

Open CenterViewController.m and add the following block of code to btnMovePanelRight::

UIButton *button = sender;
switch (button.tag) {
	case 0: {
		[_delegate movePanelToOriginalPosition];
	case 1: {
		[_delegate movePanelRight];

You’re using a switch statement to determine if the center panel needs to move to the right or to its original center position based on the tag property of leftButton, which gets sent via the sender parameter. A button tag setting of 0 indicates that the panel has already been shifted to the right, whereas a setting of 1 indicates the panel is in its original center position.

If you check CenterViewController.xib, you’ll notice that leftButton already has its tag set to 1 for the default value.

See those calls to delegate methods? If you remember, when you setup the CenterViewController instance earlier, you set its delegate to MainViewController. These calls are to the relevant methods in MainViewController.

Before modifying those methods on the delegate, take a moment to review the protocol definitions in CenterViewController.h.

As you’ll see, there are two optional protocols and one required protocol: movePanelLeft, movePanelRight and movePanelToOriginalPosition, respectively.


It’s fairly straightforward to add these delegate methods to MainViewController, since it’s the delegate for CenterViewController.

Open MainViewController.m and add two more definitions:

#define SLIDE_TIMING .25
#define PANEL_WIDTH 60

Next locate the method stub for movePanelRight and add the following block of code to it:

UIView *childView = [self getLeftView];
[self.view sendSubviewToBack:childView];
[UIView animateWithDuration:SLIDE_TIMING delay:0 options:UIViewAnimationOptionBeginFromCurrentState
					_centerViewController.view.frame = CGRectMake(self.view.frame.size.width - PANEL_WIDTH, 0, self.view.frame.size.width, self.view.frame.size.height);
				completion:^(BOOL finished) {
					if (finished) {
						_centerViewController.leftButton.tag = 0;

Note: This is the method that ultimately gets called from the btnMovePanelRight: method in CenterViewController. For more information on delegate methods and how to implement them, please refer to Apple’s Developer Documentation.

This code is where all of the magic happens.

First, you call getLeftView. This call returns a view, which is then sent to the back and animated into place using an animateWithDuration:animations:completion: block. You can tweak the SLIDE_TIMING and PANEL_WIDTH values used in the animation to your liking. One controls the speed of the animation, while the other controls how much of the center view stays onscreen after the slide.

Another thing to note is your setting of the leftButton tag to a value of 0. If you remember, this tag setting helps track the center view’s current position. And while you already set it to 0 in the switch operation a bit earlier in the tutorial, this code ensures that you always set the tag value appropriately after the left view is animated into place.

OK… now is a great time to build and run the project. So do it!

Make sure everything is still working. When you tap on the kitties button, the center panel should slide to the right, revealing the left panel underneath. At that point, your screen should look similar to the one below:

Left Reveal

Notice the rounded corners and the shadow on the left edge of the center view – these are the results of executing showCenterViewWithShadow:withOffset:, which you added earlier.

Tap the kitties button again, and — whoops! Nothing happens. That’s because you need to add code for the complementary method, movePanelToOriginalPosition.

Go back to MainViewController.m and add the following block of code to movePanelToOriginalPosition:

[UIView animateWithDuration:SLIDE_TIMING delay:0 options:UIViewAnimationOptionBeginFromCurrentState
					_centerViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
				completion:^(BOOL finished) {
					if (finished) {
						[self resetMainView];

Once again, you use an animateWithDuration:animations:completion: block to handle the animations. This time, however, you animate the view back to its original position.

When the animation completes, you call resetMainView. Currently, that method does nothing. It needs to reset the view. So do that now!

Locate resetMainView and add the following block of code:

// remove left view and reset variables, if needed
if (_leftPanelViewController != nil)
	[self.leftPanelViewController.view removeFromSuperview];
	self.leftPanelViewController = nil;
	_centerViewController.leftButton.tag = 1;
	self.showingLeftPanel = NO;
// remove view shadows
[self showCenterViewWithShadow:NO withOffset:0];

The above removes the left panel from view, resets the tag on the kitties button (so that it now indicates that the center view is in its original position), and removes the rounded corners and shadow from the center view.

Build and run the program again. This time when you tap the kitties button, and then tap on it again, the center view goes back to its original position, as shown below:

Left Slide Back

Up next, adding the same functionality for the right side, which means… puppies!

Now Lean to the Right…

To add the right view controller, simply repeat the steps for adding the left view controller.

In MainViewController.m, add the following import statement to the top of the file:

#import "RightPanelViewController.h"

Also add this definition:


Next add the following properties within the @interface section. This will make it easier to get a handle on your right view and its current state:

@property (nonatomic, strong) RightPanelViewController *rightPanelViewController;
@property (nonatomic, assign) BOOL showingRightPanel;

Now locate getRightView, remove the existing code and add the following:

// init view if it doesn't already exist
if (_rightPanelViewController == nil)
	// this is where you define the view for the right panel
	self.rightPanelViewController = [[RightPanelViewController alloc] initWithNibName:@"RightPanelViewController" bundle:nil];
	self.rightPanelViewController.view.tag = RIGHT_PANEL_TAG;
	self.rightPanelViewController.delegate = _centerViewController;
	[self.view addSubview:self.rightPanelViewController.view];
	[self addChildViewController:self.rightPanelViewController];
	[_rightPanelViewController didMoveToParentViewController:self];
	_rightPanelViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
self.showingRightPanel = YES;
// set up view shadows
[self showCenterViewWithShadow:YES withOffset:2];
UIView *view = self.rightPanelViewController.view;
return view;

The code above is an exact duplicate of the code for getLeftView, except of course for the differences in classes and properties. If you have any questions about it, review the explanation from the previous section.

Just as before, the IBActions and IBOutlets have been connected in the interface builder file for you. The screen shot below of CenterViewController.xib shows the connections for the puppies button:

 Right Button Setup

Similar to the kitties button, the puppies button is hooked up to an IBOutlet named rightButton and an IBAction named btnMovePanelLeft:. This button controls the sliding of the center panel to reveal the right-side panel.

Time to make that panel move!

Switch to CenterViewController.m and add the following block of code to btnMovePanelLeft::

UIButton *button = sender;    
switch (button.tag) {
	case 0: {
		[_delegate movePanelToOriginalPosition];
	case 1: {
		[_delegate movePanelLeft];

Again, there aren’t a lot of differences between this code and the previous implementation of btnMovePanelRight:. You see almost the same delegate method calls.

Since you’ve already implemented movePanelToOriginalPostion, all that’s left is to add the code for movePanelLeft and tweak resetMainView to handle the right panel.

Break Hard to the Right!

Switch to MainViewController.m and add the following block of code to movePanelLeft:

UIView *childView = [self getRightView];
[self.view sendSubviewToBack:childView];
[UIView animateWithDuration:SLIDE_TIMING delay:0 options:UIViewAnimationOptionBeginFromCurrentState
					_centerViewController.view.frame = CGRectMake(-self.view.frame.size.width + PANEL_WIDTH, 0, self.view.frame.size.width, self.view.frame.size.height);
				completion:^(BOOL finished) {
					if (finished) {
						_centerViewController.rightButton.tag = 0;

This method is almost identical to movePanelRight, so there’s really no need for further explanation, is there?

Now you just need to make one more modification to account for the newly created right panel.

Locate resetMainView and replace the existing code for the method with the following:

// remove left and right views, and reset variables, if needed
if (_leftPanelViewController != nil)
	[self.leftPanelViewController.view removeFromSuperview];
	self.leftPanelViewController = nil;
	_centerViewController.leftButton.tag = 1;
	self.showingLeftPanel = NO;
if (_rightPanelViewController != nil)
	[self.rightPanelViewController.view removeFromSuperview];
	self.rightPanelViewController = nil;
	_centerViewController.rightButton.tag = 1;
	self.showingRightPanel = NO;
// remove view shadows
[self showCenterViewWithShadow:NO withOffset:0];

The only change here is the addition of the if (_rightPanelViewController != nil) block. It checks for the existence of the right panel view, identically to your previous check for the left panel view, and handles it in the same manner as before. That’s it!

Build and run the program again to make sure everything is still working. Tap on the puppies button. Your screen should look like this:

Right Reveal

Looking good, right?

But wait… there’s more! Order now and we’ll throw in some gestures, too! See the next section for details. Shipping and handling not included. :]

Move Your Hands Back and Forth

Adding gestures to your app is surprisingly simple. Don’t be intimated. You’ll do fine!


Continuing on in MainViewController.m, locate setupView and add the following line to the end:

[self setupGestures];

Next make this class a UIGestureRecognizerDelegate by adding the following line to the @interface section at the top:


The line should look like this after your change:

@interface MainViewController () <UIGestureRecognizerDelegate, CenterViewControllerDelegate>

Finally, locate setupGestures and add the following block of code to it:

UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(movePanel:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[_centerViewController.view addGestureRecognizer:panRecognizer];

The above code defines a UIPanGestureRecognizer and assigns movePanel: to it to handle any detected pan gestures. (You will write the code for that method soon.)

You configure the gesture recognizer by setting the minimum and maximum number of touches and the delegate. Finally, you add the newly created gesture recognizer to _centerViewController.view.

Note: For more information about the UIGestureRecognizer class, please refer to the Apple Developer Documentation.

Didn’t I tell you that’d be simple? There’s only one move remaining in your slide-out routine.

Now Move That View!

The gesture recognizer calls movePanel: when it detects a gesture. So your last task for this tutorial is to implement that method.

movePanel: makes use of two properties: showPanel and preVelocity. Add these two properties to the @interface section of MainViewController.m:

@property (nonatomic, assign) BOOL showPanel;
@property (nonatomic, assign) CGPoint preVelocity;

Locate the stub for movePanel: and add the following block of code to it (it’s a big one!):

[[[(UITapGestureRecognizer*)sender view] layer] removeAllAnimations];
CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self.view];
CGPoint velocity = [(UIPanGestureRecognizer*)sender velocityInView:[sender view]];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
        UIView *childView = nil;
        if(velocity.x > 0) {
            if (!_showingRightPanel) {
                childView = [self getLeftView];
        } else {
            if (!_showingLeftPanel) {
                childView = [self getRightView];
        // Make sure the view you're working with is front and center.
        [self.view sendSubviewToBack:childView];
        [[sender view] bringSubviewToFront:[(UIPanGestureRecognizer*)sender view]];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
        if(velocity.x > 0) {
            // NSLog(@"gesture went right");
        } else {
            // NSLog(@"gesture went left");
        if (!_showPanel) {
            [self movePanelToOriginalPosition];
        } else {
            if (_showingLeftPanel) {
                [self movePanelRight];
            }  else if (_showingRightPanel) {
                [self movePanelLeft];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateChanged) {
        if(velocity.x > 0) {
            // NSLog(@"gesture went right");
        } else {
            // NSLog(@"gesture went left");
        // Are you more than halfway? If so, show the panel when done dragging by setting this value to YES (1).
        _showPanel = abs([sender view].center.x - _centerViewController.view.frame.size.width/2) > _centerViewController.view.frame.size.width/2;
        // Allow dragging only in x-coordinates by only updating the x-coordinate with translation position.
        [sender view].center = CGPointMake([sender view].center.x + translatedPoint.x, [sender view].center.y);
        [(UIPanGestureRecognizer*)sender setTranslation:CGPointMake(0,0) inView:self.view];
        // If you needed to check for a change in direction, you could use this code to do so.
        if(velocity.x*_preVelocity.x + velocity.y*_preVelocity.y > 0) {
            // NSLog(@"same direction");
        } else {
            // NSLog(@"opposite direction");
        _preVelocity = velocity;

The code includes comments explaining its functionality. Here are a few more key things to understand:

  • There are three states that need to be tracked: UIGestureRecognizerStateBegan, UIGestureRecognizerStateEnded, and UIGestureRecognizerStateChanged.
  • translationInView: returns the point as a position within the coordinate system of the specified view, and assigns this value to the translatedPoint variable, which is used to set the view’s position.
  • velocityInView: returns the velocity of the pan gesture in points per second. This helps in finding changes in direction.

You can move the center, left and right views around using a combination of these three states, as well as find the location and velocity/direction of the pan gesture.

For example, if the gesture direction is right, then show the left panel. If the direction is left, then show the right panel. You should be able to see what’s happening at each stage just by looking at the code and, more importantly, by reading the comments.

Build and run the program again. At this point, you should be able to slide the center panel left and right, revealing the panels underneath. If everything is working… you’re good to go!

Left Reveal Right Reveal

Where to Go from Here?

Congratulations! If you made it all the way through, you’re a slide-out navigation ninja!


I hope you enjoyed this tutorial. Feel free to download the completed project file.

As I mentioned earlier, if you prefer a pre-built library over the DIY solution, be sure to check out SWRevealViewController. This library is straightforward to use. Check out the developer’s instructions here.

Drop by the forums to share your slide-out moves and grooves!

Tammy Coron

Tammy Coron is a writer, musician, artist, and software engineer.

As an independent creative professional, Tammy spends her time developing software, writing, illustrating, and reminding others that The Impossible Just Takes A Little Longer. She also hosts the Roundabout: Creative Chaos podcast.

For the most part, Tammy is always working; she’s a contributor on Creative Bloq, iMore, and (of course!) When she’s not earning a living, Tammy enjoys spending time on her farm – in Tennessee – with her husband and their two sons.

Interested in reading more about Tammy?

User Comments


[ 1 , 2 , 3 , 4 , 5 , 6 ]
  • Hi All,

    This may be a silly question but i m new in IOS development. My center view is table view I am unable to scroll it what will be the issue

  • Hi All,

    I am new in IOS development this tutorial is great for beginners. One of my question is I am trying to add tableviewcontroller as a center viewcontroller It get added perfectly but its not scrolling to next cells
  • Sorry for so many comments but the page was not refreshing or showing comments my issue is resolved now. I replaces Pan gesture with edge gesture
  • Yea, Hi, can some one tell me if this would work if I have multiple screens ? And what I would need to do in order to make that work. As I understand, there is only one option to make that work, and that is to change the self.centerViewController property in mainviewcontroller. Even then there would be some problems with setting the delegate back to main for the next controller to call the movePanelLeft and movePanelRight. Also It would not have the animated effect of changing screen (not unless you implement that explicitly).
    I came here to learn how to create such panel, the current made ones will not do for me, because I needed a one in which left Panel would come above the center and center would not move from it's place. If any1 have a link to such already made (Keeping in mind that it has to be present on all screens, not just one), please share. Any help would be appreciated. Thank you very much in advance.
  • Beautiful tutorial very helpful there is also a good tutorial on to create Slide and push menu using jQuery and CSS ... ry-css.php
[ 1 , 2 , 3 , 4 , 5 , 6 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Our Books

Our Team

Swift Team

... 13 total!

iOS Team

... 54 total!

Android Team

... 9 total!

OS X Team

... 11 total!

Sprite Kit Team

... 9 total!

Unity Team

... 8 total!

Unreal Engine Team

... 2 total!

Articles Team

... 9 total!