What is the most important thing when we design and create our apps?
 
Colors, shapes, design, feature list, architecture, implementation, code quality and somewhere there a simple thought crosses your mind—how is the user going to interact with my app? Is it intuitive enough? Is it smooth enough?
 
As an iOS dev you know how important is to make your app pretty and resemble the real world in behavior, while also being intuitive and convenient.

Well, so do we. This is exactly why we are building our components in a way that allows both a great experience with the stock feature set and an option for easy customization, so you can fully realize your own ideas.

In this post, we’re going to mix together one of our components, a couple of natural laws and a good bit of imagination—and see what happens.

Show More, Code Less—or TKSideDrawer in Action

TKSideDrawer—this beautiful component saves us so much space with our menus and simultaneously looks so cool in our apps. It’s not just an ordinary space saver though—it offers polished animations and transitions, and it is highly customizable.
 
It is exactly the high level of customization you will benefit from today. Using the UIKitDynamics framework, you will learn how to create a cool bouncy animation and plug it into TKSideDrawer. Ok, no more sweet talk, let’s get to the real deal.

First, open Xcode and create a new Single View Application:

Xcode - Single View Application

Now open the ViewController.swift file. Create a TKSideDrawerView and a navigation bar with a button that will open the side drawer. Next, add the navigation bar as a main view to the side drawer.

Insert the following two sections with a couple of items in each, just for demo purposes:

class ViewController: UIViewController {
 
    let sideDrawerView = TKSideDrawerView()
    let navItem = UINavigationItem()
     
    override func viewDidLoad() {
        super.viewDidLoad()
        sideDrawerView.frame = self.view.bounds
        self.view.addSubview(sideDrawerView)
        self.view.backgroundColor = UIColor.yellowColor()
         
        let navBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: CGRectGetWidth(sideDrawerView.mainView.bounds), height: 44))
        navItem.leftBarButtonItem = UIBarButtonItem(title: "CLICK", style: UIBarButtonItemStyle.Plain, target: self, action: "showSideDrawer")
        navBar.items = [navItem];
        navBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth
        sideDrawerView.mainView.addSubview(navBar)
         
        let sideDrawer = sideDrawerView.sideDrawer
        sideDrawer.fill = TKSolidFill(color: UIColor.grayColor())
        sideDrawer.width = 200;
        sideDrawer.content.backgroundColor = UIColor.clearColor()
         
        var section = sideDrawer.addSectionWithTitle("Primary")
        section.addItemWithTitle("Social")
        section.addItemWithTitle("Promotions")
         
        section = sideDrawer.addSectionWithTitle("Label")
        section.addItemWithTitle("Important")
        section.addItemWithTitle("Starred")
        section.addItemWithTitle("Sent Mail")
        section.addItemWithTitle("Drafts")
    }
 
    func showSideDrawer()
    {
        sideDrawerView.sideDrawer.show()
    }
}
Just a few lines of code and you have a ready-to-use side drawer. It’s as simple as that.


SideDrawer for iOS

This is the default behavior of TKSideDrawer.

You can use some of the predefined transitions to generate a different behavior. If you’re interested, you can read more about them in our online documentation. Now we’re going to dive into a bit deeper waters.

Physics, Gravity and TKSideDrawer

The trend in mobile apps is to resemble the real world more and more closely. We are armed with tons of libraries and frameworks in our everyday fight to deliver an intuitive, useful and rich user experience.

One of our most precious weapons here is UIKit Dynamics. This is the magic that handles our complicated physics equations. This library takes away the great pleasure that is reading and studying physics ourselves, giving us a few useful objects and methods that practically do the job for us instead—as I said, it’s magical. Knowing that, you can create a cool, custom transition for the TKSideDrawer with some help from UIKit Dynamics.
 
Create a new class and give it a name, for example CustomTransition. Keep in mind that it has to be a child class of the TKSideDrawerTransition class. In the new class you should override two methods:

  • -(void) show
  • -(void) dismiss
The three objects that you should define as shown below come from UIKit Dynamics.

The UIDynamicAnimator is the beating heart of the library itself, producing realistic animations thanks to the built-in physics engine. To do its job, the UIDynamicAnimator needs to be given UIDynamic behaviors to work with. The dynamic behaviors actually represent real world physical behaviors implemented into the programming universe. In the demo we are going to use two dynamic behaviors—UIGravityBehavior and UICollisionBehavior.
 
  • UIGravityBehavior applies gravity to the added UIViews
  • UICollisionBehavior handles the collision between objects or an object and a boundary (a screen boundary or such defined by us)
There is one more important class—UIDynamicItemBehavoir—which adjusts properties regarding other behaviors, like velocity, elasticity, density, etc.

class PhysicsTransitionManager: TKSideDrawerTransition {
 
    var animator : UIDynamicAnimator!
    var gravity  : UIGravityBehavior!
    var collision : UICollisionBehavior!
     
    override init(sideDrawer: TKSideDrawer) {
        super.init(sideDrawer: sideDrawer)
        animator = UIDynamicAnimator(referenceView: (sideDrawer.superview)!)
        gravity = UIGravityBehavior(items: [sideDrawer])
        collision = UICollisionBehavior(items: [sideDrawer])
    }
     
    override init()
    {
       super.init()
    }
     
    override func show() {
 
    }
     
    override func dismiss() {
        
    }
}
Before you begin implementing the CustomTransition class, you need to tell the TKSideDrawer that you want it to use our special transition. So, open the ViewController.swift file and in the ViewDidLoad method right under the line where you have set the side drawer’s width to 200, add the following line:
 
sideDrawer.transitionManager = PhysicsTransitionManager(sideDrawer: sideDrawer)

Okay, now that you have a basic knowledge of UIKitDynamics we can start implementing our -show method. You are going to make the side drawer slide in from the left side of the screen and collide in a pretty way with the navigation bar.
 
First, set the side drawer’s frame outside of the screen boundaries so that you can achieve the slide-in effect from the left. Then initialize the UIDynamicAnimator with a reference view, and the UIGravityBehavior with the sideDrawer as an item. Now you have to set up the gravity direction. As I said, we want a slide-in effect from the left and the default value of the gravity direction vector is (0.0, 1.0), which means the objects on which gravity is applied are basically falling down exactly the same way the real world gravity works. That’s not exactly what we need, right?

We need our sideDrawer to be moving horizontally from left to right rather than vertically, so set the gravity direction vector to (1.0, 0.0):

override func show() {
    self.transitionBegan(true)
    self.sideDrawer?.frame = CGRect(x: -200, y: 0, width: (self.sideDrawer?.width)!, height: (self.sideDrawer?.superview?.bounds.height)!)
    self.sideDrawer?.hidden = false
     
    self.animator = UIDynamicAnimator(referenceView: (self.sideDrawer?.superview)!)
    gravity = UIGravityBehavior(items: [self.sideDrawer!])
    gravity.gravityDirection = CGVector(dx: 1.0, dy: 0.0)
 
    animator.addBehavior(gravity)
}
If you build and run your project, you will get this result:


SideDrawer with UIKitDynamics

Not quite as expected, huh?

This happens because now we have gravity applied to the view and it is moving, but there is nothing to stop it—we don’t have any boundaries.

Go back to the implementation of the -show method and at the end of it paste the following lines of code:

collision.addBoundaryWithIdentifier("Bound", fromPoint: CGPoint(x: 200, y: 0), toPoint: CGPoint(x: 200, y: (self.sideDrawer?.superview?.bounds.height)!))
animator.addBehavior(collision)
 
let itemBehavior = UIDynamicItemBehavior(items: [self.sideDrawer!])
itemBehavior.elasticity = 0.4
animator.addBehavior(itemBehavior)
self.transitionEnded(true);
You have just initialized the collision behavior and have set a boundary, which will be like an invisible wall for our side drawer. It will hit the boundary and then bounce back until it loses its force. You have also created a UIDynamicItemBehavior with the side drawer as an item and have set the elasticity property to 0.4, which is the amount of elasticity applied upon collision between objects. Its values are from 0.0 for no bounce at all to 1.0 for completely elastic collision.

Build and run your app again​:
 
SideDrawer with UIKitDynamics and Collision

Close enough, right?

Now the side drawer is doing exactly what we want it to do, but let’s make it look like it collides with the navigation bar not with thin air. The only piece missing here is the movement of the navigation bar, and you can implement that as a simple animation a bit quicker than the movement of the side drawer. Finally, the -show method should look like this. Build, run and let’s see the result:

override func show() {
    self.transitionBegan(true)
    self.sideDrawer?.frame = CGRect(x: -200, y: 0, width: (self.sideDrawer?.width)!, height: (self.sideDrawer?.superview?.bounds.height)!)
    self.sideDrawer?.hidden = false
     
    self.animator = UIDynamicAnimator(referenceView: (self.sideDrawer?.superview)!)
    gravity = UIGravityBehavior(items: [self.sideDrawer!])
    gravity.gravityDirection = CGVector(dx: 1.0, dy: 0.0)
 
    collision.addBoundaryWithIdentifier("Bound", fromPoint: CGPoint(x: 200, y: 0), toPoint: CGPoint(x: 200, y: (self.sideDrawer?.superview?.bounds.height)!))
    animator.addBehavior(collision)
     
    animator.addBehavior(gravity)
 
    let itemBehavior = UIDynamicItemBehavior(items: [self.sideDrawer!])
    itemBehavior.elasticity = 0.4
    animator.addBehavior(itemBehavior)
 
    UIView.animateWithDuration(0.5, animations: { () -> Void in
        self.sideDrawer?.hostview?.center = CGPoint(x: (self.sideDrawer?.hostview?.center.x)! + (self.sideDrawer?.width)!, y:(self.sideDrawer?.hostview?.center.y)! )
        }) { (finished) -> Void in
            self.transitionEnded(true)
    }
}

SideDrawer with UIKitDynamics shows

Nice, but we still don’t have our dismiss transition defined. Given everything we went through so far and the fact that dismiss is simply the opposite of show, you might wonder just how hard can it be?
 
Exactly, it’s not hard at all. You already have everything set up so all you need are a few lines of code.

You have to move the navigation bar to its initial position, with the only difference being that you now need a slower animation so that the navigation bar follows the side drawer.

Flip the gravity direction to the opposite side, remove the previous boundary and add a new one outside of the phone screen:

override func dismiss() {
    self.transitionBegan(true)
 
    UIView.animateWithDuration(0.9, animations: { () -> Void in
        self.sideDrawer?.hostview?.center = CGPoint(x: CGRectGetMidX((self.sideDrawer?.hostview?.superview?.bounds)!), y: CGRectGetMidY((self.sideDrawer?.hostview?.superview?.bounds)!))
        }) { (finished) -> Void in
            self.transitionEnded(false)
    }
     
    gravity.gravityDirection = CGVector(dx: -1.0, dy: 0.0)
    collision.removeAllBoundaries()
    collision.addBoundaryWithIdentifier("leftBound", fromPoint: CGPoint(x: -250, y: 0), toPoint: CGPoint(x: -250, y: (self.sideDrawer?.superview?.bounds.height)!))
}
There you go our final result:


SideDrawer with UIKitDynamics

You can experiment with different directions and dynamic behaviors. Try implementing a vertically falling side drawer with or without a moving navigation bar. You can find the project demonstrated in this article in our Demo apps GitHub repo.

Of course, in order to run the project, you need UI for iOS. Get a free trial here.

Happy coding and... may the force be with you.


sophialazarova164164
About the Author

Sophia Lazarova

Sophia Lazarova is a Junior Developer in the Telerik iOS Team. She recently graduated from the Telerik Academy with flying colors to join the team and start adding value to the suite of the best iOS controls. She is passionate about software development in various technologies.

Related Posts

Comments

Comments are disabled in preview mode.