Make App Pie

Training for Developers and Artists

Add an Animated Drawer

You’ve probably seen menus that pop out of the side of an app, but do you know how to make one? With the knowledge of some simple code you too can add these to your application using auto layout.
If you take a look at the example file, I’ve set up a storyboard for you.

 

There’s a few buttons and a subview with more buttons. Open up the constraints.

 

You’ll see I’ve set the blue subview Drawer up with a bottom and a trailing constraint, the width and the height. The trailing constraint is flush with the superview, so when closed, it is closed completely. If you click on the constraint, you’ll also see I set up an outlet for the constraint, I’ll connect the trailing constraint to the outlet, letting me control where the trailing edge is of the subview.
To describe the closed and open states of the drawer, I have two methods. The closed drawer makes the drawer disappear by with an alpha of 0 and make the trailing constraint outside the visible view. I reverse the process for the open drawer. For a closed drawer I’ll dd this code:

drawer.alpha = 0.0
isOpen = false
drawerTrailingConstriant.constant = -(drawer.frame.width)

I’m going to add one more thing here. To animate a constraint you need to call for a layout change. You do that with the layoutIfNeeded method of UIView.

view.layoutIfNeeded()

To reverse the process, I’ll copy and paste this code in the openedDrawer, change the alpha to 1.0 the flag to true, and the constant to 0.
I made these methods so I can do both animated and non animated opening and closing. I’ll start the app with a closed drawer, so I’ll place in viewDidLoad

closedDrawer()

Finally, I’ll toggle between the closed and open drawer states. I’ll use the very flexible UIViewPropertyAnimator class for this. I already set up an if statement to decide when the drawer is open or closed.

if isOpen{

 } else {

}

Inside the true block, I’ll add:

let animation = UIViewPropertyAnimator(

There’s several animation options here. There are the standard animation curves like ease in, ease out, and linear. There’s also some customization options, which we’ll use here. For a drawer, and other UI moving on and off stage, you’ll find a spring based animation works well. That’s the one with a damping ratio. Damping ratios control how springy the end of the animation has. Add this:

let animation = UIViewPropertyAnimator(duration: 1.0, dampingRatio: 0.2) 

In the closure, I’ll close the drawer

{
    self.closedDrawer()
}

I’ll add to start the animation

animation.startAnimation()

I’ll do the same for the opened drawer, so I’ll copy and paste this. However, I’ll give values that will give us the proper effect. Somewhere between 0.85 and 1.0 works well over one second.

let animation = UIViewPropertyAnimator(duration: 1.0, dampingRatio: 0.85) {

In the closure I’ll change this to open.

   self.openedDrawer()
}
animation.startAnimation()

We are ready to run. Set the simulator to iPhone XR. Run the app.

Tap the options button and you’ll get the drawer opening. Tap again and the drawer will close, though very bouncy. Notice even the alpha is bouncing. Try some other values on your own. With this basic setup you can make many different styles of drawers with different personalities.

The Whole Code

Here’s the listing for this project. You can also download the project from GitHub here

//
//  ViewController.swift
//  AnimatedDrawer
//
//
//  An exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//

import UIKit

class ViewController: UIViewController {
    private var isOpen = true //The state of the drawer
    @IBOutlet weak var drawerTrailingConstriant: NSLayoutConstraint!
    @IBOutlet weak var drawer: UIView!
    
    //toggle the state of the drawer
    @IBAction func openCloseDrawer(_ sender: UIButton) {
        if isOpen{
            let animation = UIViewPropertyAnimator(duration: 1.0, dampingRatio: 0.2) {
                self.closedDrawer()
            }
            animation.startAnimation()
        }else{
            let animation = UIViewPropertyAnimator(duration: 1.0, dampingRatio: 0.85) {
                self.openedDrawer()
            }
            animation.startAnimation()
        }
    }
    
    // Code the state of the drawer here.
    func closedDrawer(){
        drawer.alpha = 0.0
        isOpen = false
        drawerTrailingConstriant.constant = -(drawer.frame.width)
        view.layoutIfNeeded()
    }
    
    func openedDrawer(){
        drawer.alpha = 1.0
        isOpen = true
        drawerTrailingConstriant.constant = 0
        view.layoutIfNeeded()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        //Start with a closed drawer
        closedDrawer()
    }


}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: