Creating a sliding menu in Swift

Another productive week has passed at Hackership, and I have been able to learn about very interesting topics, like databases during a SQL vs NOSQL workshop (with some interesting debate about why you should never ever use mongoDB), or soft skills like best practices in networking, which can be summarize in:

  • filling up your github
  • participating to hackathons and meetups (technical and non technical) and conferences
  • Posting on Stack overflow
  • Posting on twitter
  • Joining  Xing
  • Joining tech related groups on Linkedin (recruiters use it to find people)
  • Having business cards to hand out

And this week with the help of my mentor I finally managed to debug my sliding menu, which was surprisingly simple, once you know how to do it! I previously followed a tutorial and did one by hand, when there are awesome libraries out there which provide what was missing in mine, for example the possibility to have a navigation controller to have back buttons without breaking the sliding menu.

I had to remove all the navigations bar I put manually since I couldn’t use a navigation controller, and redo a lot of the autolayout as most of my constraints were relative to the nav bar (NB: ALWAYS  put the constraints to the superview so in case you remove the nav bar it doesn’t break the entire layout!).  Here is a little summary on how to implement (nicely) a sidebar menu.

 

How to implement a sliding menu in swift

After reading about different options I chose to use MMDrawerController, because of its simplicity and very good performances. To install it, follow these simple steps:

  1. Add to your podfile the following line: pod ‘MMDrawerController’ ,  then run pod install in command line (for more information about how to use cocoapods, check out my previous article)
  2. We use the version without Storyboard support because it’s the most recent one. However, the extension with storyboard is very useful, so go to the github project, download the zip and copy `MMDrawerController+Storyboard.m` and `MMDrawerController+Storyboard.h` into your project. You can then go into you bridging header and add the following:
    #import <MMDrawerController/MMDrawerController.h>
    #import "MMDrawerController+Storyboard.h"
    #import <MMDrawerController/UIViewController+MMDrawerController.h>
    #import <MMDrawerController/MMDrawerBarButtonItem.h>
  3. Now you can go ahead and create the sliding menu in the storyboard. Create a new `UIViewController`, give it the class `MMDrawerController` and make it also the root controller. Once it’s done, create the view controller which will hold your menu. In my case, it’s a `UITableView`. Then create a segue from `MMDrawerController` to it, and give the segue the class `mm_left` if you want your sliding menu on the left, or `mm_right` if you want it on the right. It should look like this:
    Capture d’écran 2015-07-21 à 22.03.41
  4. Next create your first view controller (the one you would like to be displayed when you open the app), and embed it in a navigation controller, by clicking in the menu on “Editor” -> “Embed in” -> “navigation controller”. You can then make a segue to this navigation controller from `MMDrawerController`, and give it the class `mm_center`. The center controller will be the controller from which you will make the menu slide in and out. The overall storyboard should look a bit like this:
    Capture d’écran 2015-07-21 à 22.14.33
  5. Put a menu button in your center view controller, and add this action to it:
     @IBAction func menuTapped(sender: UIBarButtonItem) {
            self.mm_drawerController.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion: nil)
        }
  6. Now if you click on it the sliding menu should appear on the left. To make the menu load different view controllers (the one you want to display in your menu), go back to your `tableViewController`, and add the following code (adapted of course to what you want to return):
    override func viewDidLoad() {
            
            super.viewDidLoad()
    
            let item1 = NavigationModel(title: "PEOPLE", icon: "icon-home")
            let item2 = NavigationModel(title: "CONVERSATIONS", icon: "icon-chat", count: String(self.messagesUnread))
            let item3 = NavigationModel(title: "FRIENDS", icon: "icon-star")
            
            items = [ item1, item2, item3]
    
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 3
        }
    
     func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
            
            if indexPath.item == 0 {
                
                let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("PhotoGridController") as! PhotoGridController
                
                let navigationController = self.mm_drawerController.centerViewController as! UINavigationController
                
                navigationController.viewControllers = [viewController]
                
                self.mm_drawerController.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion: nil)
                
            }
            if indexPath.item == 1 {
                
                let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("ConversationListTableViewController") as! ConversationListTableViewController
                
                 let navigationController = self.mm_drawerController.centerViewController as! UINavigationController
                
                navigationController.viewControllers = [viewController]
                
                self.mm_drawerController.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion: nil)
    
                
            }
            else if indexPath.item == 2 {
                
                let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("FriendListViewController") as! FriendListViewController
                
                let navigationController = self.mm_drawerController.centerViewController as! UINavigationController
                
                navigationController.viewControllers = [viewController]
                
                self.mm_drawerController.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion: nil)
                
            }
    }
    
    

    So what this code does it to replace the first view controller we created above with the other controllers we have in our storyboard, with the advantage of getting them by this way also embedded in a navigation controller (which will thus allow back buttons). Remember that for `instantiateViewControllerWithIdentifier` to work you have to specify an identifier for this particular controller in the storyboard. I usually use the class name to avoid getting confused.

  7. Finally a couple of nice options you can add to make the mmdrawercontroller even nicer, swipe to open and close it, and tapping anywhere in the center view controller to close it (you can find the full list of options on github). Add in you app delegate, in `didFinishLaunchingWithOptions`:
    let window = application.windows.first as? UIWindow
    let drawer = window!.rootViewController as! MMDrawerController
    drawer.openDrawerGestureModeMask = MMOpenDrawerGestureMode.PanningCenterView
    drawer.closeDrawerGestureModeMask = MMCloseDrawerGestureMode.PanningCenterView | MMCloseDrawerGestureMode.TapCenterView

     

Here you are, with a very nice sliding menu in swift with just a few lines of code! Don’t hesitate to drop me a line if something is unclear, and or check out my next article about image caching and custom alerts in swift 🙂