Blog

Back to Blog

Navigating the SlidingPanel

Posted on 4 Feb 2013 Written by Chris Grant

The ShinobiEssentials Sliding Overlay (SEssentialsSlidingOverlay) gives you an easy way to drop a sliding overlay into your project. This is increasingly becoming one of the most popular navigation patterns in iOS development, with apps like Facebook, Path, Gmail and Twitterrific (to name just a few) all following this navigation pattern.

SlidingDcovery, National Parks and Path are just a few examples out of a large number of apps that make use of the side bar navigation pattern.

This post shows you how to implement this pattern in your own iOS application using the SEssentialsSlidingOverlay. The SEssentialsSlidingOverlay is based solely on UIViews for flexibility, but it can be easily extended to work with UIViewControllers and UINavigationControllers. I’ve used ARC for this sample project to keep things simple, but you can easily use the same pattern if you are doing your own memory management.

You can download the source of the project here, which may be useful when following the tutorial below. You’ll need a copy of the ShinobiEssentials Framework to use with this project. If you don’t have it already – download a trial version.

SlidingOverlayController

To achieve this, we need three simple classes. The first is the Sliding Overlay Controller. This is a UIViewController subclass and is responsible for the interaction between the menu view, toolbar view and the navigation controllers. The first step in this controller is to add a SEssentialsSlidingOverlay to the view, in the viewDidLoad method:

slidingOverlay = [[SEssentialsSlidingOverlay alloc] initWithFrame:self.view.bounds andToolbar:NO];
[_slidingOverlay setUnderlaySizeType:SEssentialsUnderlayPixelSize];
[_slidingOverlay setUnderlayRevealAmount:250];
[[self view] addSubview:_slidingOverlay];

Note that I’ve initialised it with my view’s bounds, specified that I want a fixed size for the underlay, set that size to 250, then added it to my view. If you run the app now – you should see a sliding overlay in place. I’ve also hid the toolbar. We want our navigation controller’s toolbar to appear rather than the custom Shinobi one – that way we get nice sliding animations when a view is pushed, as well as setting the title.

We must then set up the different navigation controllers that we need. We need a navigation controller for each navigation path. I’ve created one for each of my menu buttons. Feed, Profile, Messages and Friends. To initially populate these, I’m using four simple view controllers that I’ve defined in the “Placeholder Views” group. These are simply to demonstrate the structure of the app. You should delete them and replace them when it comes to creating your own Sliding Overlay Controller.

Whenever we want a navigation controller to become active, we call the following method, passing in the navigation controller and whether we want the menu to toggle once it has been added.

-(void)showController:(UIViewController*)controller andToggleMenu:(BOOL)shouldToggleMenu {
    if(_activeViewController != controller) {
        for (UIView *subview in [[_slidingOverlay overlay] subviews]) {
            if ([subview respondsToSelector:@selector(removeFromSuperview)]) {
                [subview removeFromSuperview];
            }
        }
        [[_slidingOverlay overlay] addSubview:controller.view];
        [self correctFrame:controller];
        
        _activeViewController = controller;
    }
    
    if(shouldToggleMenu) {
        [self toggleMenu];
    }
}

This method checks that the controller passed is not active (in which case it will do nothing) – removes all subviews from the SEssentialsSlidingOverlay’s overlay view, and then adds the passed controller’s view to the SEssentialsSlidingOverlay’s overlay. It also corrects the height of the frame, taking in to account the status bar. We also store the controller as the active view controller – so we know what is currently on screen. Finally, we toggle the menu if the shouldToggleMenu parameter was YES. This works great, and allows the user to retain their position in multiple navigation controllers.

Menu View

We now need to add some buttons so we can call this showController method. We could add buttons manually by adding them in code to the SEssentialsSlidingOverlay’s underlay view and hook them up to the method that way, but to keep things separate I’ve added a MenuView class. I’ve added this to the underlay in my controller’s viewDidLoad property:

MenuView *menuView = [[MenuView alloc] initWithFrame:_slidingOverlay.underlay.bounds];
[menuView setMenuDelegate:self];
[[_slidingOverlay underlay] addSubview:menuView];

Defining the menu in a separate class allows for greater encapsulation. The MenuView class is responsible for displaying the buttons that allow you to access each of the navigation controllers. It has a delegate property which is an object that conforms to the MenuDelegate protocol. In our case, that object is the SlidingOverlayController. This means that the four buttons added can simply call their corresponding methods on the delegate when they are tapped. The MenuDelegate protocol looks like this:

@protocol MenuDelegate
-(void)showFeed;
-(void)showProfile;
-(void)showMessages;
-(void)showFriends;
@end

You should modify this to suit your application, but the existing protocol can give you a good idea of how it should work. The MenuDelegate protocol is implemented by the SlidingOverlayController, which shows the appropriate navigation controller.

-(void)showFeed {
    [self showController:_feedNavController andToggleMenu:YES];
}

This involves slightly more code than defining everything in the SlidingOverlayController, but allows for a cleaner design and greater encapsulation. We now have everything we need in place to start using our sliding overlay with a left menu that switches out the current visible navigation controller. However, we are not done yet!

To enable other classes to be able to control the opening / closing of the left underlay, the SlidingOverlayController conforms to another protocol:

@protocol OverlayDelegate
-(void)toggleMenu;
@end

OverlayNavigationController

You may have noticed that all of the UINavigation controllers created in the SlidingOverlayController are instances of OverlayNavigationController. I’ve added this class to add a menu button to the left hand side of the navigation bar by default which can open and close the menu button. It does this by having an overlayDelegate property, which is an object that conforms to the previously described OverlayDelegate protocol. The class sets the navigationItem’s leftBarButton to a “Menu” button in it’s initWithRootViewController constructor. When the button is tapped, the toggleMenu method on the delegate (the SlidingOverlayController) is called and the menu will open/close.

-(id)initWithRootViewController:(UIViewController *)rootViewController {
    if(self = [super initWithRootViewController:rootViewController]) {
        UIBarButtonItem *menu = [[UIBarButtonItem alloc] initWithTitle:@"Menu"
                                                                 style:UIBarButtonItemStylePlain
                                                                target:self
                                                                action:@selector(toggleMenuPressed)];
        [[rootViewController navigationItem] setLeftBarButtonItem:menu];
    }
    return self;
}

-(void)toggleMenuPressed {
    [[self overlayDelegate] toggleMenu];
} 

And that’s it! You should be able to simply grab the code, drop the SlidingOverlayController, MenuView and OverlayNavigationController classes into your project, replace the boilerplate view controllers, and have a sliding overlay that supports multiple branches of navigation!

I OS Simulator Screen Shot 28 Jan 2013 16.21.55

If you haven’t already, download the source of the project here to help you get started with writing your own navigation controller based sliding overlay.

Back to Blog