Hamburger Menu

 

Background

Hamburger menus are traditionally an Android thing, but often a client wants Android and iOS to look the same, and sometimes that means iOS implements a Hamburger menu. There are many different ways to skin this cat. I think the simplest and best way is with a custom transition and a normal push segue over the current context. I’ll show you what I mean.

Download Sample Project on GitHub

 

MenuViewController

Create a MenuViewController with a sidebar, whatever buttons you want, and a background view constrained far offscreen to the right. Set that background view to be black and alpha 0, and then connect an @IBOutlet. As the push segue happens and we fade in the background, we want the “fade view” to cover the entire width.

Hamburger Menu

Connect a UITapGestureRecognizer to the BackgroundView with an @IBAction to close.

class MenuViewController: UIViewController {
    
    @IBOutlet weak var fadeOutView: UIView!
    
    @IBAction func close(_ sender: Any) {
        dismiss(animated: true, completion: nil)
        UIView.animate(withDuration: 0.25) {
            self.fadeOutView.alpha = 0.0
        }
    }
    
    override func viewWillAppear(_ animated: Bool) {
        UIView.animate(withDuration: 0.25) {
            self.fadeOutView.alpha = 0.75
        }
    }
}

 

SocialViewController

Create a SocialViewController with a button connected to an @IBAction.

Hamburger Outlet Action

 

In the @IBAction instantiate MenuViewController and set transitioningDelegate to self.

@IBAction func menu(_ sender: UIButton) {
    
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    
    guard let menuController = storyboard.instantiateViewController(withIdentifier: "MenuViewController") as? MenuViewController else {
        return
    }
    
    menuController.transitioningDelegate = self
    present(menuController, animated: true, completion: nil)
    
}

 

Conform to UIViewControllerTransitioningDelegate and add a SlideOverAnimator().

class SocialViewController: UIViewController, UIViewControllerTransitioningDelegate {
    
    let transition = SlideOverAnimator()

 

SlideOverAnimator

Create a new class SlideOverAnimator.

import UIKit

class SlideOverAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    
    let duration = 0.3
    var presenting = true
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }
    
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        let animatingView = transitionContext.view(forKey: .to) ?? transitionContext.view(forKey: .from)!
        
        if presenting {
            animatingView.transform = CGAffineTransform(translationX: -animatingView.frame.size.width, y: 0)
        } else {
            animatingView.transform = CGAffineTransform(translationX: 0, y: 0)
        }
        containerView.addSubview(animatingView)
        
        UIView.animate(withDuration: duration, delay:0.0, options: .curveEaseInOut, animations: {
            
            if self.presenting {
                animatingView.transform = CGAffineTransform(translationX: 0, y: 0)
            } else {
                animatingView.transform = CGAffineTransform(translationX: -animatingView.frame.size.width, y: 0)
            }
        }, completion: { _ in
            transitionContext.completeTransition(true)
        })
        
    }
}

And you’re done.

Hamburger Menu

Download Sample Project on GitHub