Twitter Slide Menu

We will breakdown, analyze the Slide Menu mechanism of Twitter app, and try to replicate it using Auto Layout and Container View. No third party library is used in this project.

 

Main screen of Twitter app consist of a tab view controller. If you swipe right, a side menu will appear.

side menu and tab bar

 

When the side menu is open, both side menu view and tab bar view appear in the same screen. The screen (which is a view controller) contain both of the side menu view controller and tab bar view controller :

container view

We can achieve this using two container view in the Main View Controller.

 

You can download the Slide Menu Starter project here.

 

The steps below will start from the starter project.

 

Setup Container View for Tab bar controller

To accomodate the side menu and tab bar controllers, we will create a new view controller in storyboard named MainViewController , and drag a container view to it.

 

create new file

mainVC

 

Drag container view

 

After dragging, you will see that Xcode auto link a new view controller to the Container view. We don't need this new controller, select the link (segue) and press delete to remove the link, then delete the attached view controller.

selectSegue

 

Then we will link the container view to the tab bar view controller. Select the Container view, then hold control and drag it to the tab bar controller. Select "Embed".

 

controlDrag

 

select embed

 

You might see the tab bar controller shrinked to match the container view size 😱, no worries, we will add some constraint to the container view so that it will match the screen size.

 

Let's create a leading space 0 , top space 0, equal width and equal height constraints for the container view (to its parent view) like this :

Constraint gif

Select the container view, Hold control and drag to its parent view. Then once the list of constraints appear, hold shift to select multiple constraints, then click 'Add Constraints' once you are done.

 

As by default Xcode align the top / bottom constraint to Safe Area, the container view will have some margin on top when viewed in iPhone X / XR / XS :

Safe Area

 

We want the container view to align to the screen top, not safe area, hence we will need to edit the constraint.

 

Select the container view and double click its Align Top constraint :

Double click top constraint

 

Change the "Safe Area" in First/Second Item to "Superview", and then set the constant to 0 .

Safe Area

 

constant zero

 

After adjusting the top constraint, remember to set the constant of leading constraint to 0 as well.

 

Set the MainViewController as the initial view controller.

initial view controller

 

Build and run the app, you now should have a container view containing the tab bar controller 🙌.

 

super view

 

As we will add another container view for side menu later on, we should give a label to the tab bar container view so we can identify it later. Let's label it as ContentView.

label content view

 

Setup Container View for Side Menu View Controller

Similar to previous section, drag another container view to MainViewController, link it to the side menu view controller, setup constraints (top 0, leading 0, equal width and equal height) and change the safe area to superview.

 

container view

 

 

Add a label to this container view, we will label it as SideMenuView.

side menu label

 

As we want the width of side menu to be 80% of screen width (so the side menu won't cover the whole screen when opened), we will change its equal width constraint to equal 80% of its parent view's width.

 

Select SideMenuView , then click on 'Edit' on its Equal width constraint, change the multipler to 0.8 . This will make the side menu view width to be 80% of its parent view.

 

proportional width

 

Build and run the app, you should see the side menu is overlapping the tab bar controller like this :

side menu run

 

Now we have two container view on the main view controller 🙌!

 

As we are going to setup the top left profile button in the next step, let's move the side menu to the left so the tab bar controller is visible. We will set the leading constraint value of the side menu container to -350 for now.

side menu leading

 

Later we will create outlet for the leading constraints of these two container view so we can manipulate their horizontal position.

Setup top left profile button

Notice that for every tab in the tab bar controller, they have the same top left profile button (the rounded avatar on top left) like this :

top left profile button

 

To reduce the repeating work of creating the top left button for each of the tab, we can create a View Controller class named 'ContentViewController', and then subclass view controller in each tab to it.

create new file

 

content VC

 

We will add the following code to the ContentViewController.swift to create the left top profile button :


 

And then we replace the UIViewController subclass to ContentViewController subclass for HomeViewController, SearchViewController, NotificationViewController and MessageViewController.








 

Build and run the app, we have a top left profile button for each tab now 👌!

 

top left profile button

 

 

Create outlet for constraints

To be able to modify the constraint value in code, we need to create and link outlet of constraint to the MainViewController.

 

Select the Side Menu Container View in storyboard, double click the leading constraint, then hold control + drag the highlighted constraint to the view controller. Name the outlet as sideMenuViewLeadingConstraint.

 

double click constraint

 

control drag to view controller

 

side menu view constraint outlet

 

Repeat the same step for the leading constraint of Tab Bar Container View (ContentView), and name the outlet as contentViewLeadingConstraint.

 

Create an outlet for the Side Menu Container View, name it as sideMenuContainer .

Your MainViewController.swift should look like this now :


 

Toggle side menu when top left profile button is tapped

When you tap on the top left avatar circle button on Twitter app, the side menu appears if it is not visible yet, or the side menu disappear if it is currently visible. Now we are going to replicate this functionality.

 

Add a boolean variable to keep track if the side menu is visible on screen.


 

In viewDidLoad, we set the leading constraint of side menu container to negative width of the side menu container. So that the side menu container will be invisible at first.

 


 

side menu leading explanation

Next, we will add a function to toggle the side menu :

 


 

Then in the ContentViewController, we toggle the side menu when the profile button is tapped :



Build and run the app, now we have toggle-able side menu 🤘!

toggling

 

In the next section, we will add slide gesture to show/hide menu, and segue to profile view controller when one of the table view row in side menu view controller is tapped.

 

 

Create Pan Gesture to detect finger pan

As the side menu will move according to the distance we swiped in the app, we will create a Pan Gesture recognizer to capture the movement of finger on the ContentViewController (which every view controllers in tab bar are subclassed from, so the pan gesture will apply on each of them).

 


 

Here's the output of the translation when panned :

pan output

 

When user's finger move right, the translation's X value is positive; when user's finger move left, the translation's X value is negative.

 

We will add some code to the handlePan function to modify the leading constraint values of Side Menu Container View and Tab bar Container view :


 

Build and run the app, and try dragging to the right :

Pan stuck

When we release the drag / finger , the side menu is stuck on the last position we dragged! 😬 . When you release finger in the middle of drag on the Twitter app, it should continue to move until the menu is fully opened / closed. Next, we will add some code for this 'snap-to-nearest' feature.

 

Modify the handlePan function to include the 'snap-to-nearest' feature :


 

Build and run the app, and try to release while dragging. The side menu should snap to fully open / close position now 🤘.

panSnap

 

We have successfully added the swipe to open/close gesture for the side menu, Awesome!

Next, we will add some menu to the side menu's table view, and add action to segue when it is tapped.

 

Setup before coding the segue

For the segue, we will push the profile view controller to the navigation controller of the selected tab.

The code (no need to type this first, this is just an explanation of what we will do later) :


 

To identify which navigation controller to push the profile view controller to, we will need to create a variable to hold this value. Let's name it currentActiveNav :


 

Next, we will need to add an identifier to the profile view controller (or any other controller you want to segue to) in the Storyboard. So that we can instantiate this view controller in code like this : storyboard.instantiateViewController(withIdentifier: "ProfileViewController").

storyboard identifier

 

Next, we will implement the hideSideMenu() function in the MainViewController :


 

Next, we will modify the toggleSideMenu(fromViewController:) function in the MainViewController. We want to set the value of currentActiveNav to the navigation controller of the selected tab when the menu is shown.


 

After typing the code above, you will get an error mentioning "Value of type 'MainViewController' has no member 'sideMenuViewController'", this is because we haven't add the sideMenuViewController variable to the MainViewController yet. We will proceed to add it like this. :

 


We have finished preparing for the setup, next, we will setup the table view and implement the tap action in the side menu.

Setup Table view and row tap action

Let's create an outlet for the table view in the side menu view controller (hold control and drag), and name it menuTableView.

 

create outlet

 

create outlet 2

 

Also create a variable cellIdentifier to hold the identifier for cell reuse :


 

In viewDidLoad, set the table view datasource/ delegate to self :


 

Then implement the datasource / delegate method :


 

Build and run the app, open the side menu and tap on any row, you should see this :

push segue

 

You have now implemented Twitter slide menu without using any library / Cocoapods 🎉! Container views helped us a lot on implementing the slide menu, now you can use one less library when you want to implement slide menu 🙌.