The Gourmet iOS Developer's Cookbook: Dynamic Animators
Dynamic animators are some of the most exciting elements of iOS, even if they are among the least practical. Their physics-based view behaviors create lively and curious interfaces. At the same time, they can be fussy to work with. They don’t happily coexist with Auto Layout because they directly update frame values and can rotate views. That said, dynamic animators are tremendously fun. They help make your UIs pop and are well worth exploring to discover what features they can provide your users.
The UIDynamicAnimator class emulates interface “physics.” It coalesces this functionality into distinct behaviors like snapping, pushing, attachment, and collision. Here’s a quick overview of the primitive UIKit dynamic behaviors:
- Attachments— UIAttachmentBehavior instances tie a view either to a position or to another view. It’s basically a virtual string with a set length, although you can make it act more like a spring by updating damping and frequency properties.
- Collisions— UICollisionBehavior instances allow views to collide with each other or with path-based boundaries. In a collision, energy can be passed from one item to another, and a view’s trajectory can be changed.
- Gravity— UIGravityBehavior instances apply acceleration to views. You set where “down” is and allow the gravity vector to act on velocities over time.
- Pushes— UIPushBehavior instances add an impulse force to views, adding new energy to the system.
- Snaps— UISnapBehavior instances act as magnets, drawing views to attachment points.
- Dynamic items— UIDynamicItemBehavior is the odd man out in this list. Instead of acting as a force, dynamic items are objects affected by forces. These behaviors enable your views to participate in the other behaviors listed here. You can attach, collide, push, snap, and weigh down views by treating them as having physical properties. The dynamic item behavior defines density, elasticity, friction, and resistance and manages linear and angular item velocities.
You can best explore how these items work by running Apple’s UIKit Dynamic Catalog sample code (https://developer.apple.com/library/ios/samplecode/DynamicsCatalog). This sample code illustrates available dynamic behaviors, presenting a wide range of effects you can create in your own apps. Most importantly, it lets you see, interact with, and explore each behavior on its own.
Once you’ve finished exploring Apple’s dynamics catalog, start building your own examples. To begin, you need to create a dynamic animator, like this:
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
This top-level class acts as an intermediary between your views and any dynamic behaviors you add to the system. The animator provides context for the animations, establishing either a reference view to create a coordinate system or a reference layout when working with collection views.
Typically, you use a view controller’s primary view as a reference, although you are not limited to this. Use any view backdrop that’s large enough to contain the actors in your drama. And, as you’ll see, you can extend animated views beyond the parent view, if needed.
Delegation enables you to know when an animator pauses, an important tool for tracking the end of an animation sequence. An animator delegate declares the UIDynamicAnimatorDelegate protocol and conforms to that protocol by implementing the optional dynamicAnimatorDidPause: and dynamicAnimatorWillResume: methods. Assign a delegate like this:
self.animator.delegate = self;
When you implement a delegate, you know when animation sequences coalesce, which enables you to clean up your simulation after the physics have come to a static resting point. Be aware that some animations may never “stop,” especially those that do not employ energy-lowering strategies like friction and resistance.
Creating and Adding Behaviors
Each dynamic animator can coordinate many behaviors at once. For example, you might want to create a dynamic system where views “fall” in the direction of gravity but bounce off each other and remain within the boundaries of the view controller’s view. Or you might create a snapping behavior that involves collision detection, bumping some views out of the way.
Add each behavior to the animator with the addBehavior: method. This method applies the behavior to the current state. If the animator is active, the behavior will immediately start. The following snippet creates a new snapping behavior and adds it to an animator:
UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:testView snapToPoint:point]; [self.animator addBehavior:snapBehavior];
The standard behavior-creation pattern is to allocate an instance and initialize it with one or more items. This example uses a single item (testView) and sets a single parameter, a snap-to point. When this is added to the animator, the view moves until its center co-aligns with the snap point.
Each dynamic behavior is distinct in terms of the details associated with the class’s API. Gravity behavior initializers accept an array of child items, although you can add and remove items at later times. Attachment behaviors include a suite of initializers that supply anchor points, dynamic items, and offsets away from the anchors. Each behavior class is a new adventure, and it’s well worth your time to read through their APIs as they are all quite different from each other.