Adding dynamism with UIKit Dynamics

Most apps implement simple animations, like the ones you saw in the last couple of sections. However, some animations might need even more realism. This is what UIKit Dynamics is for. With UIKit Dynamics, you can place one or more views in a scene that uses a physics engine to apply certain forces to the views it contains. For instance, you can apply gravity to a particular object, causing it to fall off the screen. You can even have objects bumping into each other, and if you assign a mass to your views, this mass is taken into account when two objects crash into each other. When you apply a certain force to an object with very little mass, it will be displaced more than an object with a lot of mass, just like you would expect in the real world.

Let's take a little break from building Hello-Contacts and use a separate app to implement a nice, little physics experiment! Create a new project and name it Cradle. Make sure to configure the project so it only runs in landscape orientation. In Main.storyboard, make sure to set the preview to landscape and add three square views to the view controller's view. Make each view about 100 x 100 points and give them a background color. Normally, you would set up constraints to position these views. However, since you're just experimenting right now and the resulting code will be a lot simpler if you don't set up constraints, you can skip setting up constraints for now.

Your layout should look similar to the following screenshot:

Create instances of @IBOutlet in ViewController.swift for the views you just added and connect them to the storyboard in the same way you did before. You can name the outlets square1, square2, and square3 if you want to follow along with the code samples.

The simplest thing you can implement at this point is to set up a scene that contains the three squares and apply some gravity to them. This will cause the squares to fall off the screen because they'll start falling once gravity is applied and there is no floor to stop the squares from dropping off the screen.

To set up a scene like the one described here, add the following property to ViewController.swift:

var animator: UIDynamicAnimator!

Then, in viewDidLoad(), add the following:

override func viewDidLoad() {  
  super.viewDidLoad()  

  let squares: [UIDynamicItem] = [square1, square2, square3]  
  animator = UIDynamicAnimator(referenceView: view)  
  let gravity = UIGravityBehavior(items: squares)  
  animator.addBehavior(gravity)  
}

If you test your app now, you'll notice that your views start falling immediately. Setting up a simple scene such as this is easy with UIKit Dynamics. The downside of this simple example is that it's not particularly interesting to look at. Before you add features to make this sample more interesting, let's see what the preceding four lines of code do.

The views in a dynamic scene must be of the UIDynamicItem type. UIView can be used as UIDynamicItem, so by adding them to a list that has [UIDynamicItem] works automatically. Then, you create an instance of UIDynamicAnimator and you tell it the view to which it will apply its physics engine. The last step is to configure and apply a behavior. This sample uses UIGravityBehavior but there are several other behaviors you can use in your scenes.

For instance, you can create UIAttachmentBehavior to attach an item to another item or to some point on the screen. The following code implements an attachment behavior for every square on the screen and attaches it to the top of the screen. This will cause the squares to fall for a moment and then they will bounce and swing a little until they eventually come to a standstill. You can add the following code to viewDidLoad() to implement this:

var nextAnchorX = 250

for square in squares {
  let anchorPoint = CGPoint(x: nextAnchorX, y: 0)
  nextAnchorX -= 30
  let attachment = UIAttachmentBehavior(item: square, attachedToAnchor: anchorPoint)
  attachment.damping = 0.7
  animator.addBehavior(attachment)
}

Every square is set up with a slightly different attachment point in this example. Note that the attachment behavior has a damping property. This damping is similar to the damping that is used in spring animations. Try experimenting with the value for attachment.damping to see what it does.

If you run the app now, you'll note that every square is attached to an invisible point on the screen that keeps it from falling. Some things are still missing though. The squares can now simply cross over each other. It would be a lot cooler if they bumped into each other instead.

All you need to do is add the following two lines to viewDidLoad():

let collisions = UICollisionBehavior(items: squares)  
animator.addBehavior(collisions)

Are you convinced that UIKit Dynamics are cool yet? I thought so; it's amazing how much you can do with just a little bit of code. Let's add some mass to the squares and make them more elastic to see whether this has any effect on how the squares collide.

Update the for loop from before by adding the following code:

for square in squares {  
  //…  

  let dynamicBehavior = UIDynamicItemBehavior()  
  dynamicBehavior.addItem(square)  
  dynamicBehavior.density = CGFloat(arc4random_uniform(3) + 1)  
  dynamicBehavior.elasticity = 0.8  
  animator.addBehavior(dynamicBehavior)  
}

The preceding code should augment what you already have in the loop; it shouldn't replace the existing logic. By setting a density on UIDynamicItemBehavior, the engine can derive the mass of an item. This will change how the physics engine treats the item when it collides with another item.

If you build and run now, you won't see a huge difference. However, you can tell that the animation has changed because the variables that go into the physics simulation have changed. Even though this example was very simple, you should be able to implement some interesting behaviors by creating an animator and playing around with the different behaviors you can add to it. Have a look at Apple's documentation for a full overview of all available behaviors and possibilities.

Even though the UIKit Dynamics physics engine is powerful and performant, you should not use it to build games. If you want to build a game, have a look at SpriteKit. It has a similar, powerful physics engine except the framework is a lot better optimized for building games.

The last stop on your journey through animation land is view-controller transitions! Let's dive right in.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset