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