Frameworks • iOS • 47:53
UIKit Dynamics makes it easy to create animated view interactions and transitions to delight your users. Discover how animators and behaviors work by learning how to add subtle and meaningful dynamics to your app, making it stand out on the App Store.
Speaker: Olivier Gutknecht
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
[Olivier Gutknecht]
Good afternoon.
[ Applause ]
And welcome to this WWDC session on getting started with UIKit Dynamics. We think we have a great new addition to UIKit for you today. My name is Olivier Gutknecht and I'm a frameworks engineer in the UIKit team. And you might have noticed that on iOS 7, content is key.
And we'd like to offer you new ways to have better rendering and interactions with this content, and that is what dynamics is about. What are we going to cover today? First, the core concepts in architecture of dynamics. And dynamics is based on a very simple ID, combining basic behaviors. And we've see how you can actually use that to integrate new rich interactions in your applications.
But first, I'd like to make a very quick recap of animation and interaction on iOS today. Of course, almost everything we render and animate on iOS is based on Core Animation. Core Animation is an amazing animation framework. It has very strong and consistent model, extremely powerful API. And on top of that, in UIKit, we built UIView animations. Easier to use API, web integrated with the UIKit model.
And we actually include that a lot in iOS 7. We had it at UIView level keyframe animations. And we are adding spring animations to UIView animations. Another great API we have in iOS 7 is motion effects. A way to animate content based on the physical position and movement of your device. That's how we build this power act effect in iOS 7.
And when you start interacting with content, one great tool is gesture recognizer and drive changes view moving based on gesture recognizer callbacks. But, you can also use lower level APIs like CADisplayLink and animate things at screen refresh level. And of course, you can actually combine all of these techniques. So, what is UIKit Dynamics? I think somebody said yesterday that this definition was not exactly crystal clear.
It is a composable, realtime system. It's made to be-- you can subclass it. You can combine effects together, and it's physics-inspired. What kind of applications can you build with that? Well, maybe not. Hoever that was probably the most creative and completely wrong use of UISwitch ever. No, and why not? Because we have much better tool for you. Sprite Kits, it's a great new game framework. It's available on iOS and OS X. It's a great foundering engine.
And we actually use the same physics engine. So then, where can you use dynamics in your applications? I have a very quick demo I'd like to show you. This is a very simple likable example. I can organize my pictures. And, as you pay attention, when I'm dragging a picture by the center, it moves as expected. But when I drag by the corner of this picture, it will react the way you would expect when dragging something in a table. So we have natural real world looking interactions. I can select pictures to the bottom of the screen.
I can throw this to start organizing things. But, maybe we can find something easier actually. So let's create new albums and start organizing these albums. OK. That's -- that's much better. So that's a good example of using dynamics in a non-game application. So of course, that's a WWDC demo app. How complex is that? Actually, not that much.
You enter your application, all implementation files and no cheating. It's about for 400 lines of code. But what's interesting here is I have a lot of code here to load these images, have this nice picture views. The actual interaction code is about 80 lines of code. So that's really easy. And most of it is in this cute magnet effect.
[ Applause ]
So, let's start exploring dynamics. But first, why? We wanted to provide a way to [inaudible] model real world inspired interactions. And we wanted also to provide a way to combine quick canned animations, predefined animation and interactions. And we wanted to offer you something that's really was at UI level. And there is a good example of that, the lock screen.
In iOS 6, do you still remember iOS 6? OK. In iOS 6, when you tap this camera button, you have the small bounce animation, right, to show there is actually a Camera UI behind. And then you can drag, so that's going up to review it. And you can actually end that gesture or cancel, and the lock screen is going fall down.
What's interesting is, in iOS 6, these two modes are completely separate. There is a predefined animation for the tap bounce effect. And because it's a completely predefine animation, you cannot catch with a gesture the lock screen in flight while it's animating. And seen in iOS 6, when you end that gesture interactive part, the lock screen just animate down, it doesn't bounce.
That's not what we want. So in iOS 7, let me show you. So that's when I tap the camera button. I slide up and cancel, it bounces. I slide up and I'm going to [inaudible] the view, the bounce is slightly different. So that's a good example of [inaudible] interaction you might want to add in your application.
How? When we start to thinking about this API, an interesting question was, where should we add that? And one idea was, "Maybe should just add new methods to UIView, like setMass, applyForce." That's interesting, but we realize that's not what you want to express. You want to express high level effects.
You don't want just to mess with these use and forces and everything. You want a high level more the clarity of expression of these interactions. So then, we ask the concept we use all over the place in UIKit and in all of our frameworks' composition. And in dynamics, we compose Predefined behaviors for you own behaviors.
In this lock screen example, the bouncing, falling down and bouncing effect. Why do I really need to express that? I need gravity towards a view falling. And I need a collision to get this bounce effect. So, in dynamics, I would express that as one view being popped off two primitive behaviors, gravity and collision. And all these behaviors ran are associated in animation context.
So if we start digging in the architecture, what we add is first that's new class, UI DynamicAnimator which provides the context, and then you associate behaviors, UI DynamicBehavior subclasses to this animator. And usually then, you associate views to these behaviors. And one key concept here is, usually, you want to view to be part of two or more behaviors 'cause that's going to combine the effect of these behaviors.
The other thing we need is what we call Reference View which was a way to define the global coordinate system, in which we would run this interaction with the only constraint that the views we animate are actually subviews or part of the view hierarchy of that reference view.
So that's-- see in more details what we have in animators and behaviors. UIDynamicAnimator provide your overall context for your animation and defines the coordinate system. And we'll see later, that's quite interesting. And it wraps the underlying engine and we know when to start and stop that engine for you.
It also keeps track of all the behaviors that are currently associated with this animator. It's really easy to use. You just create a UIDynamicAnimator with the reference view and then you just have to add behaviors to that. Behaviors. UIDynamicBehavior is something that is going to be associated with DynamicAnimator. It's usually associated with a view or a set of views. And we try to make behaviors as declarative as possible.
It will describe some inference view like "That view should be impacted by gravity. That view should collide." And a real interesting thing about behaviors is you can add and remove behaviors to the animator at anytime. And we'll see why that's a real key concept in dynamics. It's made to be composed. You can actually group behaviors together to define your own, also by defining in your own subclass. And it's really easy to use. Usually, you just want to allocate-alloc init a behavior usually with a set of views. And you add that behavior to the animator.
And to help you, we are providing in UIKit in iOS 7 a set of Predefined behaviors you can combine together. All of these behaviors have some common traits. First, usually, these behaviors are configured with items you want to animate. Most of this, actually you can add or remove views at anytime. So if I want a view to be no longer impacted by gravity, I just remove it from that behavior.
You can configure a behavior before or after adding it to an animator and the influence of a behavior stops as soon as you remove it from the animator itself. So what do we have? gravity, we talked about that. collisions. Attachment, a way to connect views together. We have a high level of behavior we call the Snap behavior which is a way to snap view into place.
We have a behavior, a Push behavior to apply forces to views. And we have a low level behavior which gives you a way to twitch some physics level properties of views, like friction, for instance, or density. So, let's explore this Predefined behavior. First one, Gravity behavior. So if the only thing I have in my animator is a gravity behavior with just one view, what's going to happen is that, which is expected.
It's defined by a very simple gravity vector which is uniform and global to the entire animator. We have four views which are part of this behavior. And it's controlled by x and the y components. It's expressed in the UIKit coordinate system. So, (0,1) which is the default, is gravity pointing down which is nice. And you can add and remove items at any time. It's quite easy to use. You create a Gravity behavior with a set of items and you just add this behavior to your animator.
Through this one open question, though, (0,1), which units do we use here? Well, there was a well-known constant about gravity, Earth gravity, 9.80665 [inaudible]. Who designed this API? UIKit Gravity, much better. One thousand points per second square. It feels like Earth gravity, trust me. Just easier to use points on devices.
[ Applause ]
Collision behavior, that is a really interesting one. You just add a view. You can specify a boundary. And in this case, I actually added gravity because without gravity, that would not animate, right? So, another mode is colliding between views. And of course, the third way to use Collision behavior is colliding between views and boundaries.
Views are controlled by a very simple property, collision mode. UI won't views to collide with views, views to only collide with boundaries but not with other views, or a views colliding with views and boundaries. Like gravity, you can add and remove items from this behavior at any time. So if I actually make a bottom green view disappear, what's going to happen is we will resume the animation.
And I was talking about Composition. The real interesting use case here is you can define multiple Collision behaviors, so you can express really easily things like I want red views to collide with red views, green views with green views, but not green views and red views. And a small word of warning here, it's not completely free. We steer around an engine [inaudible], so collisions do have a cost we have to detect, compute when we have collisions.
Boundaries. How do you create this? There is a really easy way which is having what you want which use that reference view we were talking about before as the default boundary. So that's a really simple property. We have a variant which-- with which you can actually apply in sets.
And we have another way to define boundaries. So you can do things like that by defining segments or even path, UIBezierPath. In that case, you have to know that we basically approximate that with a set off lines. But usually, it's OK. When you create this, you need to pass a notifier and we will see why in a few minutes.
And again, you can create a multiple behavior, multiple boundaries. There is one thing in these slides. I did show you the boundaries I was using. On device, the only thing you see is that view. These boundaries are just description of my system. They don't have an existence on screen.
We have an interesting delegate on Collision behavior. And you can be notified when we actually have a collision. So, when a view collides with a view, you can implement this method and you will get where that collision took place, and same thing for boundaries. And this is why we have this boundary notifier, so you will know which wall you collided with.
And by definition, when you get nil, it was this reference bounds easy way to set up boundaries and that is implicit bounds we pass nil. Next, Attachment behavior. This describe a view connected to an attachment point and it's really easy to use. You just pass a view and where that one should be and that's expressed in the reference view coordinate space.
We have a variant for that where you can actually connect two views together. So in this case, imagine that I then push that middle view, the system is going to react as you would expect. You can even specify where that connection is. You can specify as an offset from the center of the view where we should attach this view or these two views together. There is a nice feature in UIAttachmentBehavior. Springs. You can configure an Attachment behavior as a spring.
[ Applause ]
Just pass a Frequency and Damping and it will act as a really easy to set up spring. Another interesting feature is that attachment point can be moved. So if I move the attachment point, the view is going to move as you would expect. We also have a length property that you can change. Usually, you don't need that because we compute the length at init time.
Sometimes, you need that but you have to know when you change just in one shot, the lengths of something, it's not really physically. So, it's really not a common case. Like boundaries, these attachments are not visible in your application. It's just description of how your system should react. I'd like to show your how it feels.
[ Pause ]
So in that example, I actually added code to show you the collision boundaries and the attachment because, without that, it would just be a view moving in a very strange way of the screen. So, again, to start with a very simple attachment. So that's my gesture. So it really acts like a nonflexible small rod connected to this shape.
There is no gravity, so it's like that's green shape was just flat on a table, so I can push or pull that shape. All right. And, the other mode we have for Attachment behavior is Springs. So, let's see. It's just the same thing. I can actually push that view or pull it. And just because of that Spring effect, you don't have exactly the same animation.
[ Pause ]
Snap behavior that's a high level, really easy to use behavior. It just snaps a view at specific place on the screen and we try to get it back to non-rotated state. It looks like that. Really easy to use. Oh, you can actually customize also that dumping effect. One way to understand the Snap behavior is just like if we had set up four small springs at the corner of that view.
To create a Snap behavior, you just pass an item and a point in the reference view coordinate system, and you just add that Snap behavior to your animator. Push behavior, that's a way to apply forces. And, you just want to set up a Push behavior with a set of views.
And there is this mode parameter here. What does that mean? It means that, in this mode, we're going to apply a force which is the force will still be applied while that behavior is active in the animator. So, which means that for this view, the view is going to accelerate, right, 'cause I keep applying that force. It's defined with a very simple force vector, xComponent, yComponent, or magnitude and angle, if you prefer. And there is another interesting feature here. You can actually customize where, in that view, we apply this force.
So it's an offset from the center of the view which is the default. And if you apply a force small offset from the center is still being to push that view but you want to get this rotation effect at the same time. Units, we have a well-known unit per force Newton, which is defined as the amount of force you need to accelerate 1 kilogram to 1 meter per second squared.
[ Pause ]
[ Laughter ]
UIKit Newton. Accelerate to 100 point by 100 point view with a default density to 100 point per second squared. Should we give it a name on UIKit, [inaudible], I don't know. You don't-- we don't need a name actually 'cause it's really in Newton. Observe that we are expressing it in the UIKit unit system.
There is an also interesting feature to UIPushBehavior what we call the instantaneous mode, immediate mode. In that case, instead of applying a force, we just apply very quick impulse, which mean that this view, we immediately acquire a velocity, it's not going to accelerate over time it will just kick it a little bit. And it's going to automatically visible itself after applying it.
And if you want to reenable that again, we have the Active property. And you can set that to Yes again and you would get that [inaudible] force again. That's a great way to actually implement this tap Camera button in the lock screen. So we have gravity. Push behavior in force mode. Push behavior impulse mode. One is immediate velocity change. The other one is accelerating the view. How could we see how that works and understand better? Science. We should grab some graph paper, run some experiments and see what happens. We're going to do exactly that.
[ Pause ]
So, the first setup here is two views which we're going to add to a Gravity behavior. In that case, the relative size or density of the view will not matter. So, these views are just going to accelerate the big one and the small one at the same rate.
Now, Push behavior in continuous mode. So we will apply the same force to these two views. These two views will be part actually of the same Push behavior. One is smaller than the other one, so it's actually easier to use. So it's going to accelerate faster. Let's verify that.
Yup, that's correct. And the third mode is Push behavior in instantaneous mode. That's just at a very quick impulse these views. So, as you see, these do acquire a velocity but then that velocity doesn't change. These views are not accelerating. So if we run everything again, it feels like the last views are actually decelerating but not. It's just an effect of the other view which are indeed accelerating. So, that's difference between Gravity and the two modes we have for Push behaviors.
[ Applause ]
UIDynamicItemBehavior. This one is the last Predefined behavior we have. It's a little bit strange. It's more acting as a template you can apply to your views. With Dynamic Item Behavior, you can actually customize properties to one or many views. And what we have is friction when views are sliding one on top of the other.
We have dumpingResistance and angularResistance. And that's useful because without dumping, views would just keep moving which is usually the feel you don't want in a UI, so we have a default dumping set on views. Another interesting one is elasticity which is the restitution when you collide to the bounciness. And density which is a way to actually set a mass or a relative mass between views.
So, we cheat. We don't offer you set mass. But we do offer you set density. Fair enough. And the last one is-- whoops. So that was-- the right view was part of a UIDynamicItemBehavior which actually changed the elasticity property, so it bounce more. And we have one last property which is interesting for UI which is allowsRotation which is basically a way to cheat with the underlying engine and to actually block rotation of the items we animate. There is another really useful low level method in UIDynamicItemBehaviors, that's a way to immediately set, immediately add a given velocity to a view. And why is that useful? Sometimes, your interaction with dynamic starts after a regular gesture-based interaction.
And in this case, you add this seamless transition from the gesture-based phase to dynamics phase, you want to exactly match the gesture velocity. So you can actually inject in the system with this method, the gesture velocity itself. That's really useful. And, 'cause we use the UIKit unit system, it's expressed in points per second. Applying Dynamics.
So when you want to add dynamics through repetition, what do you need? First, you need to know which views you want to animate. You want to define what is this container or reference view you would create the animator with. And then it's really about creating the behaviors you need, adding views to these behaviors.
Next thing is configuring if needed these behaviors and associating these behaviors to animators-- to your animator, and that's it. As soon as we have a view in an active behavior and we detect that the system is not at rest, we reanimate. The other thing is when we detect that the system is at rest, we stop animating, which means that we basically stop the engine, we stop the CADisplayLink we use on those [inaudible]. So, a system at rest is not consuming CPU at all. Well, this is physics.
So, you can actually create with this API setup which don't really make sense, like if you say that this view should collide with that boundary but if the initial state of that view is completely intersecting with that boundary, you won't really have animations, right? And we are going to be slightly confused about that.
And also interesting variant with Collision behavior is if you try to add all these views in this very small enclosed space, it's not going to work 'cause we basically can't compute a correct solution for that setup. And in all-time coverage, when you have a view blocked by a boundary and you try to apply an infinite force, this will not break your device.
So, when I-- what I usually suggest when you're building systems with dynamics is to build that step by step. Start with one behavior, add your views, configure that behavior, see how that reacts, add another behavior, see what's changing, see-- check if the actual interactions feels right, and then keep adding or tweaking your behaviors. If you start by constructing this incredibly complex set of behaviors in the configuration or the [inaudible], and if that doesn't work, that's not really easy to actually understand what's [inaudible].
So in this case, just remove one-by-one your behaviors to understand which one was actually causing the problem. Did I mention that we are sometimes cheating with physics? This is not a physics-accurate simulation tool. Do not use that to control your Evil Genius Space Station. That is your configuration that we do not support explicitly. And that's really a core concept of dynamics. But I'd like to show you a few additional things.
The first one is what we call Dynamic Items. You may not notice that, in this presentation, I was talking sometimes about views, sometimes about items, sometimes-- most of these methods actually were init with items. So, views or items? UIDynamicItem is actually a protocol. And what's great about that is it describes what we need for something associated with a Predefined behavior to be animated.
And what UIKit needs to animate something in dynamics is actually pretty basic. We need to be able to actually move an item. We need to know the size of this item because we need that for correct forces, computation, or collisions. And an object without a size is again not really physics. And we need to animate a rotation because the only thing we animate is 2D rotations.
Guess what, UIView actually implement that UIDynamicItem. Center, transform, bounce, that's all we need. But because of that's actually a protocol, you can implement that. You can define your own dynamic item. Your own classes implementing UIDynamicItem, and we will just call center and transform on this. It's actually a really simple protocol. I can add everything on just one slide. The thing we need is we need to know the initial state for an item.
So we need to know the position. We need to know the size. We need to know the initial rotation only to the rotation. And then, when we animate on each [inaudible], we basically call center and transform. And that's how we animate things. Actually, there is another class in UIKit when you set a position to transform and which has a size, and that's not UIView.
CollectionViewLayoutAttributes. You can use dynamics which UICollectionView and the way it works is UICollectionViewLayoutAttributes which is what we use when you define your own layout to describe where a given cell is going to add on screen. That class we introduced in iOS 6 actually implements UIDynamicItem. And when you want to create an animator to actually animate parts of a layout, you just create that with the layout itself instead of passing a reference view.
For the layout is going to define a size CollectionView button size and that's all we need. And then when you want to create your own behaviors, instead of passing views, just pass your UICollectionViewLayoutAttributes instances. And we're going to animate this. And because you passed through layout at alloc-init time, we will derive the layout in validation itself. Which also mean that when we detect that a system is at rest, we want to invalidate your CollectionViewLayout. So that's Dynamics and UICollectionView.
[ Applause ]
[ Pause ]
That's a CollectionView. Actually, that's a subclass of a well-known UICollectionViewLayout. You might know UICollectionViewFlowLayout. Well that was just a subclass of this. And what can you do is a CollectionView with a data source in a CollectionView. You can add new elements, right? So let's do that .
[ Pause ]
[ Applause ]
[ Pause ]
To conclude, UIKit Dynamics is really an interaction-oriented animation system. The best way to use dynamics is to create this small additional effects are going to make your application more alive and have this natural feel. And that one good thing to keep in mind is to notify your key elements and animate this.
Again, it's really about focusing on the user experience. What can make your app even better? We have UI Dynamics recommendation in the UIKit Prerelease Library. We have another session about UIKit Dynamics and I'm going to explore how to create real effects by combining behavior and creating your own UI Dynamic behavior subclass. We have some related sessions custom transition using View Controllers.
And you can actually use dynamics with View Controllers transition [inaudible] about that. And we have-- or if you're indeed, game oriented two sessions about SpriteKits. We have a dedicated dynamics lab [inaudible], come talk to us, and we can't wait to see what you're going to do with that. Thank you. [Applause]