Frameworks • iOS • 56:46
Go beyond the basics to learn how to combine dynamic behaviors to create rich interactions. Discover how to apply dynamics to view controllers, collection views, and your own view subclasses to create engaging layouts and transitions. Learn best practices to keep your app responsive and performing well.
Speakers: Olivier Gutknecht, Bruce Nilo
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Good afternoon. Welcome to this WWDC session on Advanced Techniques with UIKit Dynamics. We have a lot of content for you today, many lines of code. So let's get started. We're going to start with a very quick recap of dynamics, architecture, and we're going to explore more of this "combining behaviors" idea.
And we're going to talk briefly again about dynamic items, custom dynamic items. And we have a quick example about collection view and dynamics. And we will end with great demo and architecture about using view controllers with dynamics. So UIKit Dynamics. It's a physics inspired animation and interaction system.
Made to be composable, combinable, reusable. We try to use Dynamics in a way which is declarative. You tell us what the intent of the interaction is and we will try to combine the effect of all new behaviors to animate things on screen. Let me stress that this does not, in anyway, replace what we have to day with Core Animation, UIView animation, or motion effects. It is just a new tool for rich, real-world like interactions.
So the base Dynamics architecture, we have this DynamicAnimator which gives us this context in which we associate various behaviors and we associate dynamic items which are usually views or collection view layout attributes. And the key thing here is, an item might be part of different behaviors and we're going to combine all these effects. So let's talk about UIDynamicAnimator.
So its main job is to track behaviors and animated items. And it wraps the underlying physics engine we run for you. What's interesting is, we try to actually optimize that engine. So if we detect that the system is at rest, we just stop. If you change anything like changing the parameter on one of your behaviors, we start the system again. And you can actually be notified.
We have a UIDynamicAnimatorDelegate, so you can implement methods so you can know if we are about to pause or resume that system. You can use a DynamicAnimator in three modes basically, with views which is the common case. In collection views-- collection view layout exactly, and you can implement your own dynamic item to participate in dynamics. So let's talk about combining behaviors.
Combining behaviors is interesting: the underlying model physics is in itself quite good about combining things, combine two forces and you get a force. And we build on that, we have this base class UIDynamicBehavior that you can subclass. And one of few things we have in this class is the ability to add child behaviors, which means that you can use this class to construct your own high-level behaviors.
What's interesting here, if you attach behavior directly to the animator, or if you add a child behavior to a behavior and add this behavior to the animator, there is no difference. There is no CPU cost or any runtime difference between these two approaches. So there is no cost for building your abstractions.
[ Pause ]
You can compose your behaviors statically like by defining your own class, adding child behaviors and then never changing these behaviors again or dynamically by adding and removing children for a behavior or from the animator. So let's see a quick example of that. Let's say that I want to drag with this real-world effect a view and when my gesture ends, I want to apply gravity to get this bouncy effect I love so much. The initial setup was just with a collision behavior and that view added to this behavior. But when my gesture actually begins, what I want to do is to create a new behavior, an attachment behavior, add that to the animator.
And when I update-- when my gesture is updated, I just need to change that attachment point in my UIAttachmentBehavior and it's going to drag the view as I would expect. When I end this gesture, what I just need to do is to remove the attachment behavior and at the same time add the same view to a gravity behavior. A collision behavior is still here, so we are going to add this fall and bounce effect.
That's a really interesting concept and you can build a lot of completely different effects by combining behaviors. For instance, that example I was using in the first session, a bounce effect is just gravity and collision at the same time. If I want to drag a view and then at the end of the gesture snap it somewhere else in the screen, I can use an attachment behavior first and then a snap behavior.
Something like the Lock Screen in iOS 7 can be built as a combination of collision, gravity, attachment, and push behavior. But you can imagine many other things like a magnet-like behavior that you could build from multiple UIPushBehaviors. So I'd like to show you a very quick demo of the different feel you can get by changing, removing, and adding behaviors.
So a very interesting thing here is the top right animator label is turning green when the animator is active. I basically just implemented this UIDynamicAnimatorDelegate so we will know when the animator actually stops and starts again. So I can just drag that view, there is no other behaviors, just collisions. So let's add gravity. So now, when I actually move this view, the effect is, of course, completely different. It's moving a little bit too much, motion sickness is not something that I would like to have in this demo.
So we're going to add a UIDynamicItemBehavior which is a way to set up some low-level properties. I'm going to set up resistance which a way to apply damping on velocity. So the feel is completely different. I could add a force behavior going to the right, an immediate instantaneous impulse behavior and keep my attachment behavior. So I see that this force on the view that's trying to move it to the right, so let's stop that.
And the other thing is I could also change those that are low-level property on this view like the elasticity which is the restitution on collision. So we have a view which is obviously really happy [laughter] to be here. So let's just turn off collisions and that's the end of this demo.
[ Applause ]
And each action was just really add or remove behavior. So what do that means? It means that the effect you want is really about building a behavior tree. And the behavior tree can be using predefined behaviors like a collision behavior. But maybe your own behavior is like a magnet-like behavior or a drag behavior which are going to be built on top of these predefined behaviors.
And then you need to associate items to these behaviors, and that is something that you can do at your high-level behavior API level. You could directly add the same items to predefined behaviors or only add just one to something just for a while when I want to drag this item. How do you build your own behavior? You just have to subclass UIDynamicBehavior.
And let's say I want to implement, again, this BouncyFallBehavior. I'm going to define initWithItem initializer. How do I implement that? The first thing I need is to actually create the sub-behaviors for my high-level behavior, so I need gravity and collisions here. If needed, I will configure this collision behavior. And the last thing is adding these two behaviors I just created as children to myself. And that's it. When I need to use my high-level behavior, I am just going to actually add alloc init that new behavior and add it to my animator.
[ Pause ]
So something which is useful when you're building your own behavior is to think in terms of API. What is the API you want to define on such an interaction behavior? It could be something really simple like initWithItems, like what we did just a minute ago, and we'll see another example in this session when you can actually define a more complex API.
It's useful to think about how that is going to integrate with your existing application flow, like if you already have a gesture, it's always a good thing to match the ending gesture velocity with the system you're creating in dynamics. And if you need that, it's not always the case, but if you need that, you can define per step actions.
It's just a block, you can define on UIDynamicBehavior and we're going to invoke that block with each simulation step. So that's interesting when you want to, for instance, change the force based on an item position, to implement magnets for instance. Of course, because we are running that with each simulation pick, you have to be careful about what we do-- what you do in this block.
There is one catch about combining behaviors, it's this UIDynamicItemBehavior class you can use to setup properties to your items. With UIDynamicItemBehavior, you can change density, damping, you can block rotation, you can change friction or elasticity, and I was using that in my previous demo. And there is no problem about combining many UIDynamicItemBehavior, especially if you are using-- if you're configuring distinct properties in each, because that's not going to conflict, right? If you do want to change the same property in different UIDynamicItemBehavior, that's still possible, but we have to decide which one we pick. And the last one wins. We actually have quite a precise definition of what the last one is.
It's a pre-order depth first walk of the behavior tree. Get it? Let's check that rule on an example, right? So here is my behavior tree. I have a few behaviors I don't care about and three UIDynamicItemBehaviors configuring elasticity and friction, but the question is what are the actual venues in my dynamic item? So let's walk the behavior tree.
We start with default. So first behavior is not a dynamic item behavior, so we don't care. That one, we don't care. That one is interesting, that's the first UIDynamicItemBehavior we have in this tree walk. Elasticity is 0.5. That is new-- the new elasticity value for that dynamic item.
Next behavior, we continue. That's another dynamic item behavior, defining friction, so that's not the same property so that's OK. We just set the friction to be 0.2. And then, the last dynamic item behavior we have is setting elasticity to 0.3. That is the end value. Then now, let's actually remove this one.
In this case, we are basically going to reevaluate the behavior tree and friction is back to default. Let's add at the exact same place a UIDynamicItemBehavior changing again the same property. The new value is actually still 0.3. So that's the last, it's the most recent behavior I added, but that's not the last in this behavior tree with my definition. So that is how you can combine behaviors in a very define way.
Dynamic Items, so that's a protocol and that's a way to integrate in Dynamics things that are not necessary views or collection view layout attributes. It basically defines what we need in UIKit to animate something, so that's a position, a size, and a rotation, knowing that UIView on UICollectionView obviously implement already something like that. And we only care about 2D rotation. The engine we run is a 2D engine.
So when you are defining your own UIDynamicItem, the first time this item is added to a behavior, and that behavior is added to the animator, we would get these values, because we need to inject an initial state in the engine. Then we're going to run the simulation and each simulation tick, we're going to write position and rotation. We don't change the size of the dynamic item. If you're implementing that protocol, of course, we might write position and angle on each simulation tick. So, again, that is two methods where you should be careful about your performance.
One consequence of that is we won't care about any external change to this value after we basically grab the initial state. So one interesting question is how do you change the size of something after the effect? We don't change views, items, bodies in the engine, so you have two ways to change the size of an item, remove it from dynamics, and add it again later if you want, or cheat. For instance, if what you're animating is a view of something on the screen, you can define a subview, apply a scale transform or change the size of the subview or something like that.
Again, we need an initial state, we need to correct the initial state, so we need a size and we need reasonable position. As I said, MAXFLOAT is not a reasonable position. What can you do with that? One interesting use case for dynamic items is to sanitize or change the value we sent. You can use a single dynamic item to actually animate the same way many different things. You can map position or rotation, which are the only two values we compute to something else, like mapping to scale transform or instead of animating a rotation, animating a 3D effect.
So if you need to animate something which is not a view or a collection view layout attribute, do not define a view hierarchy on the side just to be able to use dynamics. Use a dynamic item. So let me introduce a really stupid example of dynamic item which doesn't display anything on screen, well, depends on what you call screen actually. You could just log what we compute. You could keep everything in a dictionary. You can do whatever you want with that. Let's talk about collection view.
In collection view, you can use Dynamics in three different ways. You can decide to use Dynamics for very specific animations like when you're selecting a cell and you want a very specific effect for that selection for instance. In that case, you just need to create a dynamic animator as this animation or interaction and just remove it after that. The other thing you can do is to animate a subset of a layout like you have a few cells, you want to drag these cells and after that, you're done. So you can combine animated and non-animated cells.
You can build an entire layout with Dynamics that works for, well, non-huge data source. Problem is, in dynamics, what is off screen in the system might impact what is on screen. So even if you just generate cells on screen for what is visible, you might need to simulate the entire system.
[ Pause ]
Again, you need to provide some initial state for your items and you have many ways to do that, you can compute that initial state, create layout attributes for that state, and feed that to dynamics. You can subclass an existing layout. And in the ScrollView session this morning, Josh and Eliza showed you how to actually build a Messages like effect with that technique. Or you can create and add new items on the fly.
The key here is to create the animator with your collection layout instance, add behaviors and add collection view layout attributes to these behaviors. We are then going to change position and rotation on these instances. We have some predefined, some convenient support for dynamics-- for collection view in dynamics.
We take care of invalidating the layout if anything changed in the system and we also pause and resume the animator if your layout is no longer the current layout for the collection view because in collection view, you can switch layouts. We also provide convenience method for implementing your layout so you can ask the animator itself for layout attribute for cell at index path for supplementary views and for decoration view.
So we know that's a layout so we help you in implementing this method in your layout. You can ask the animator. We have, for layout updates, the usual collection view methods, so prepareLayout is usually when you can instantiate an animator or create your initial state and prepare for update which is another layout method, you can add new items to your behaviors.
And there is this very important method in collection view which is layoutAttributesInRect which possibly basically defines where the cells are going to be. And to implement this method, we have itemsInRect in the animator. So that's really easy. You can ask the animator, "Give me all the items you're tracking in this rect." Then you can combine these items with maybe attributes which are not animated.
Again, the way you design your system will have a direct impact on the number of cells you can animate. I would like to show you an example of collection view using dynamic for a specific effect. That's actually an example from the collection view sessions last year when I was dragging a cell in a layout.
So we are going to do that the Dynamics way. So I select a few cells. So the effect is maybe a little bit too much but you get the idea. So we have these cells connected to springs and reacting to the gesture. And when I end my gesture, I just clear the animator.
[ Applause ]
How complex is that? Quite simple. You just need to decompose this program. Why do I need to animate that? The way I did it, perhaps, there are many solutions to this problem. I started with a base behavior, a single cell that I want to drag around with a spring effect, and the way I defined my behavior is four springs attached to a plane or rectangle and attached to the center of this view. So I'm going to move these four points to get the spring effect.
Then I need to be able to drag many items, right? So I'm going to define my high-level drag behavior and I'm going to do the exact same trick for all cells. Then I need a layout and I'm going to define a flow layout subclass because the basic mode of my layout is just to display a grid. It only changes when I interact with it.
So I need three classes, a DraggableLayout which is a UIColelctionViewFlowLayout. I'm going to define a simple API on this layout so I can easily connect that to a gesture recognizer, I can start the interaction with an array of index paths from a point. I can update that location and I can stop the interaction.
My high-level behavior is going to be quite similar for the API. I'm going to create a drag behavior with a set of dynamic items-- and from a point, and a way to change that location. And my low-level behavior is going to be defined with just one item I want to animate, a point and a way to update the location of this cell.
So let's see how I implemented that. Let's start with a low-level behavior. RectangleAttachmentBehavior, I configured that as an item at a given point and then it's just a matter of creating four attachment behavior, so I have this four points, I just create a spring AttachmentBehavior for each point and I add these as children behaviors.
When I want to update the location, I just need to compute again these four points and update the attachment point for my four attachment behaviors. So that's my first low-level behavior using four predefined attachment behaviors. The high-level behavior, drag behavior is actually very simple, it's all in this slide.
So what do I need? I need to pass the dynamic items I want to animate, that point. I'm going to create attachments, my low-level attachments, RectangleAttachmentBehavior. I add this as child behaviors and to update the drag location, I'm just going to basically tell my low-level behavior to update to this point. So that's it for my high-level behavior.
No more layouts. The interaction code is quite simple actually. I need to track these index paths. I want to create an animator. Then for each of these attributes, I'm going to need that initial state. So I'm going to ask flow layout which is the super class. I changed zIndex because I'm dragging this. I want this cell on top and I create my high-level drag behavior. I add this behavior to the animator. Updating the location and removing everything is extremely simple. We just update the point or clear the animator.
The layout implementation itself, "Why do I need to define which cells are in this layout for a given rect?" Some cells might not be animated. So I start by asking the super class, "Give me all the cells." Next, I want to remove the cells I'm actually animating. And then, I need to add the cells I'm actually tracking, the layout attributes I'm actually tracking, from the animator. So I use this animator itemsInRect method, and I just have to return all these attributes. And that's it, that's the entire code for this small example. Now, for some more exciting stuff, UIKit Dynamics and UIViewController Transition, I'd like to ask Bruce Nilo to show you that.
[ Applause ]
Thank you. Thank you all. Thank you, Olivier. My name is Bruce Nilo, and this stage is huge, I've never been on it before. So I don't know how many of you have been at this morning's talk. I'd like to get a good sense about custom view controller transitions.
Oh, a lot of you, OK. So I'm going to kind of breeze through a quick review of what custom view controller transitions are all about. And then, what we're going to talk about is we're going to kind of build a little bit on what-- always discussing about how to create kind of compound behaviors.
But these compound behaviors that we're going to create are going to conform to some of these new transitioning protocols that we've defined, and are going to be used to actually implement some custom view controller transitions. And we're going to walk through a couple of examples showing two different types, and you'll get a sense of how these different things compose with one another. So let's do the quick review.
First of all, the basic idea is that there's a few delegates that you create and set on your view controller directly if you're doing a present or a dismiss view controller call, or you can implement some new methods on Navigation Controller Delegate or Tab Bar Controller Delegate. And at the appropriate time when you are either pushing or popping or presenting or dismissing, we're going to ask that delegate to vend an animation controller or an interaction controller. So the methods that those objects that your delegate vends need to implement are various few. The main one for the animation controller is funny enough, animateTransition.
And for interactive transition, it's startInteractiveTransition, kind of pretty simple. These two methods are passed in a special object called the ContextTransitioning object which defines the characteristics of the transition. It defines where views start, where they end. It also is a little bit active and that we define some methods that need to be called at certain points in time. So basically, the declaration of the protocol looks something like this. There is a container view. That's the view in which the tran-- the animation takes place for the transition. There are some methods to query to find out where I'm supposed to end up.
And then, there are those action methods that are on the context. And for interactive transitions, there is a few of them. There is updateInteractiveTransition with a present, and then there's either Finish or Cancel. And finally, when the transition is all over, and this is true for both interactive transitions as well as just regular, straight up animated transitions, you must call a special method called completeTransition indicating whether canceled or not. And this basically patches up any data structures and puts things into a consistent state so your application can move forward.
It moves as a little bit to talk about the different states involved in an interactive transition. I've kind of broken it into a few sections. The first four kind of where you go from nothing, you're in no particular transition mode to the interactive mode. And you might consider this, if you're doing a pop gesture, it's as your finger is down and you're dragging across the screen. When you release that, your finger, the transition isn't over yet. It still needs to do something. It's either going to animate off or animate back to where you started. And the decision of which direction you're going in is really up to you in your code.
And so you can either cancel the transition or continue it. And once you do, you then animate it to completion and call the completeTransition method. So it's really kind of that simple and if you are interested in more details, you can look at the video of this morning's talk and there are also some docs available for that.
So, two examples that we're going to go through. One is a-- for lack of a better word, a drop in and out dialog. It's kind of a dialog which will-- you will present. It will be a custom view controller presentation. It will drop on screen. It's not going to be interactive. But what is it going to demonstrate? It's going to demonstrate using kind of a two-stage dynamic simulation where we're going to use the action methods and the DidPause methods and so forth to change the Dynamics of the system as the transition evolves.
The second demo that I'd like to deconstruct is kind of just a simple drop shade transition where I'm going to pull down from the top of the screen and I'm going to release it and either it's going to bounce up to the top or bounce down to the bottom. And the Dynamics there is fairly straightforward, but it's interesting to see how the interaction mode of the transition leverages the dynamic system and vice versa.
So let's talk about the drop in and drop out dialog a bit. So, it's a dynamic behavior that conforms to the animated transitioning protocol and it demonstrates a couple of interesting things. It demonstrates the action block which Olivier referred to. This is called on every step of the simulation, of the physics simulation.
We're going to implement a collision behavior, but we're also going to specify the collision delegate because we want to know when we've hit a certain boundary. And finally, and this is kind of interesting, we're going to implement the dynamic animator delegate. And in particular, we're interested in DidPause callback.
And we're also interested in the dynamic animator's elapsed time. Now, the reason for this is that when you're doing a transition, typically, transitions take a finite amount of time. You don't want them to take, you know, I don't know, 30 seconds to converge and go. So you might want to put a bound on it and make sure you're done in two seconds or one and a half seconds or whatever. And so typically, when you build these systems, you're kind of iteratively trying to figure out how does it look, right? But you want to actually ensure that the transition takes a certain amount of time.
And you can do that by looking at the elapsed time of the dynamic animator and checking in the DidPause and the action methods. And we're going to demonstrate that. So I'm going to show a quick demo of the drop in and out dialog. So this is kind of a demo that shows all kinds of transitions, but I'm going to show you the drop dialog.
Now, this thing comes in as little dialog. What's interesting about this is, first of all, this is on a phone and we're doing a present view controller and guess what, I can see the presenting view controller. You couldn't do this really on the phone before. So now, you can implement your kind of faux form sheets or foe popovers right on a phone.
But you'll notice that bounce that came in. So it comes in with a bounce and I'd also like to show that when we created that dialog view, before it animated in, we did something that I'm not sure if we can see it. Well, what is supposed to be shown here is some of that parallax where we layer these dialog views. And there's new API which is available, I believed, in the seed that we delivered called UIMotionEffect.
And you can put a UIMotionEffect on to a view and then animate it directly. And if it was working, I would show it to you, but it isn't so you'll have to take my word for. Now that was a present. Let's see what happens when I dismiss. Now the first thing that happens is we slide off to the side and then we bounce off and go away. That's kind of a two step simulation.
[Applause] OK. So how did we do this? Let's talk about that. So I'm going to show quickly some of the steps and there's going to be a lot of code up here, so bear with me. The YYDropOutAnimator is the animator object which is a subclass of dynamic behavior that I used to create this effect.
And everything here is just a consequence of this specific implementation and it's broken up into a few things. First of all, you'll notice that it conforms to a bunch of different protocols. It conforms to the animated transitioning. It conforms to the animator delegate and conforms to the collision behavior delegate. This is some of the power of using protocols, first of all, that you're not bound to a specific instance and you can kind of mold the objects of your choice for implementing certain behaviors in the system.
When you create this thing, you're usually create-- the delegate is usually creating it and when the delegate is asked, it's actually passed in a transition context and we scroll that away in the animator because we want to be able to use it in the dynamic behavior callbacks. We know whether or not the dialog is being presented or dismissed. And, again, the delegate, when it's called, has that information.
We set the finish time. The finish time is, I think, I was alluding to before which is I don't want this transition to take too long. So I want to say, "I want it to be done no later than this point in time," and we're going to check that value in the animator's callbacks and the dynamic behavior's action method. And finally, we're going to-- this is a composite behavior and we are going to scroll away various primitive behaviors that are actually going to be added and removed, these children behaviors as Olivier demonstrated a little bit earlier.
So, amazingly enough, I scrolled away in the corner of my office with some green felt that wasn't being used, and I used it to create kind of a visual image of what a view controller screen might look like. And basically, we're getting called with animateTransition. This is an interactive transition.
It's a straight up animation and the question is, now, how do we hook up the Dynamics to the system? Well, the first thing that we have to do is we have to figure out what's moving and what we actually want to apply forces and the like to. And a lot of this code is alighted, so I apologize for that. But there's this thing called the dynamic view. The dynamic view is the view that's moving. It's just a name.
When it's called, the first thing that we do is we add that dynamic view into the view hierarchy. It so happens that it's above the screen because it's going to drop in. And then, we start creating some of our primitive behaviors like the dynamic item behavior where we set up an elasticity, we have the dynamic view to that primitive behavior. And for the first segment of this transition, we don't want to allow any rotation. Then we add some gravity. Gravity is a pretty simple primitive behavior. It's going to be three times normal gravity.
We add a collision behavior and you'll notice that the way that I set the bounce on the collision behavior is using a slightly different method on the collision behavior, set translate reference bounds into boundaries with insets. That's actually a very useful method because you can kind of take the reference coordinate system and move it in different directions based on simple UIEdgeInsets.
So now let's talk a little bit about the finish time. Basically, we query the dynamic animator for how much time has elapsed. It so happens in this case, it's going to be 0 but, you know, for sake of being true, we ask the elapsed time then we add the duration that was scrolled away when we created the behavior object. And we create an action block and that action block is going to check whether or not the time has passed that we want to dedicate towards this transition. And if it has, there is a very simple way to finish. We basically remove ourselves from the dynamic animator.
Now, to get things going, we have to add the children behavior to ourselves, remember, we are a compound behavior. And then, we have to add ourselves and there's only one behavior now that's being added to the animator and that is us. And at this point, the physics engine is going to start and we're going to start simulating our transition.
And there you have it. So we've transitioned. We're done, it's up on the screen and now, we're going to hit the good to know button. And we're going to do the dismiss, and the dismiss is a two-stage thing. Again, we call animateTransition. We don't have to add a view into the view hierarchy. This is a dismiss, it's already there.
We're going to set our dynamic item behaviors up a little bit differently. We're going to allow rotation this time. Gravity is set up exactly the same as it was before. Our collision boundaries are a little bit different and that's because the type of animation that we're trying to achieve is a little bit different.
We're going to add an attachment behavior where we're going to kind of try to anchor-- we're going to specify a different position in the default. The default is usually the center of the item. We're going to kind of put it up to the top and we're going to put the anchor a little bit off to the side. We're going to give it a little bit of kind of bounciness.
And then, we're going to set up the action block again. And this time, it's a little interesting. First of all, there's a bug in that line where I'm setting the finish time. It really should be two-thirds of the duration not two-thirds of the elapsed time, but you get the drift. And that's because it's two stages. I'm going to spend two-thirds of my duration doing the first half of my-- or first two-thirds of my transition. And then, I'm going to move over to the next bit.
And the way again I'm going to trigger that, is I'm going to remove the behaviors which is then going to cause me to go into the DidPause animator's delegate method. I do the regular dance of adding the children behaviors. I do something different based on whether or not I'm a-- whether or not I'm presenting or dismissing, that's why there's an IF clause for the attach behavior and then we're going to run.
[ Pause ]
So now, we've come to rest. DidPause gets called. Now, it either got called because the system came to a rest or because we actually hit our elapsed time. And we're going to do the same thing. Now we're using the attach behavior a little bit as a semaphore here because the dynamic animator DidPause is saying, "Hey, do I have an attach behavior? If I do, then I need to go into the second step of my simulation." So I'm going or remove the attach behavior, clear out that reference to it.
I'm going to add myself back to the dynamic animator and I'm going to change my finish time. Now time has elapsed, so animator elapse time is actually not going to be 0 at this point. And now, I only want it to run the remaining one third of the specified duration of the transition.
At this point, since the attachments disappear-- I should have pressed that button before. Since the attachments disappear, when I run it, I'm going to hit this point. And now the collision delegate is going to kick in because now, I want to do something after that first bounce. I basically want to remove the collision behavior so that on the next drop, it's going to drop all the way off the screen.
And I want to check that I actually bounce off the edge I care about. So it's possible that I might have hit the right edge and I really want to just trigger this code if I hit the bottom. And that's what that check is doing with point.x < xContact.
But if I'm there, I'm now going to remove the collision behavior and I'm going to fall off the screen, I'm going to get back into DidPause. Now this time, I'm going to get in the DidPause definitely because time has elapsed, because basically, that view has just fallen down to the bottom of the earth. It's not going to stop.
But I put in my time check and so now I'm in the final bits of the code. I'm going to clean up and you'll notice that I call completeTransition. That's critical and that ends how that particular present dismiss was implemented. So now let's talk about the different one, this one is interactive.
It's a drop shade transition like I said. This one can actually be used the way it was implemented. It's both the navigation transition and a regular present dismiss transition. It's a dynamic behavior subclass that conforms to both animated transitioning and interactive transitioning. Again, these are protocols, so we're free to basically have one object implement the whole bunch of them if it makes sense. And in this case, it's very convenient to do so.
The interactive portion of this transition does not use Dynamics at all. However, when the interaction ends, we set up a dynamic finish as it were and the dynamic finish is actually going to be calling out to the interactive transitioning methods. And we do this for a very specific reason. We do this because that-- in that way, we are able to drive auxiliary views that might be participating in a transition, like for example, the navigation bar.
And it will synchronize in terms of how complete the transition is or not with the Dynamics of the systems. So that's a pretty interesting technique. We're going to continue to use the same DidPause mechanism that we used before. So let me give you a quick demo of that and then we'll deconstruct that one.
OK, basically, it's pretty simple. You'll see as I move this with the gesture, I can move it up or down. If I cancel it, it goes back. If you notice closely, you'll see how the navigation bar is kind of fading in and out. And if I go down, it kind of-- you'll notice that there was a slight bounce to it as it was settling. And the navigation bar itself was doing that as well.
That is a noninteractive dismissal. And just to prove my point, I can make this a full on presentation if I want to. And exact-- with exactly the same code, so that can drop in or I can flip it up. So that's what we're going to deconstruct. Let's do that quickly.
So before, the blogger's get out there, this is not some leak of new hardware. We don't have anything looking like that. I just couldn't fit all the code on the screen. So gesture starts. This has nothing to do with dynamics. We are just recognizing a pan gesture and when it starts, we're going to say Push View Controller. And this case, I'm going to through the sequence that I demonstrated as a navigation controller, and that's it.
Now, I've wired things up in such a way that when I called push view controller, my navigation controller delegate, vended in animation controller, vended in interaction controller, and all those good things were happening. And then because of that, the system called back to the interaction controller and said Start Interactive Transition.
And we put the view into the view hierarchy which is what you see with the gray box and now we are continuing to handle the gesture. And as our finger moves across the screen, we are in fact pulling the presented or the push view controller's view in the container hierarchy. And we're calling out as we do at update interactive transition with the percent complete which is based on the height of the actual view controller being presented.
So far so good. Nothing particularly new has happened until we release our finger from the screen. At which point, we're going to start building up the Dynamics of our system. We're going to determine based on velocity and direction perhaps whether or not the gesture should cancel or not.
And then, we are going to create a collision behavior using boundary insets. We're going to create an attachment behavior this time and we're going to create an action block. And what I'd like to focus on this action block is that action block is going to call UpdateInteractiveTransition. So as this Dynamics of the system affects the view as it bounces in and out, we're going to compute how close we are to the finish and we're going to call out to that UpdateInteractiveTransition method on the transition context.
When it's all over, we're going to be in the DidPause block again. We're going to determine whether or not it was canceled or not, in which case we're either going to call CancelInteractiveTransition or FinishInteractiveTransition depending on the direction. In this case, it's finish. And then, again, we're going to call the completeTransition block on our method, on the transition context.
So what did we learn here? First of all, Dynamics and custom transitions are compatible with each other. They can be used. In fact, we spend a lot of times trying to make sure that our APIs compose well together. As a rule of thumb, it really pays off to create composite behaviors that get the function that you're interested in. We showed how you can create complex dynamic transitions using the dynamic animator delegate, the collision behavior delegate, and actions on dynamic behaviors.
A dynamic behavior subclass can easily conform to one or even both of the transitioning protocols. It makes a lot of sense to do so because you can put all of the logic in one place. Duration is something that needs to be thought about when you're doing transitions. Again, a dynamic system doesn't necessarily converge ever. So you want to put checks in place based on your application logic to ensure that it finishes.
And then, what's interesting is that dynamic behavior actions can actually be used to drive the interactive portion of a transition. And that might not be entirely obvious. I'd like to make one other point and that is, is that if you're using Dynamics and you add behavior to the dynamic animator and nothing happens which has happened to me a few times, it's probably because you didn't retain your dynamic animator. Don't let that happen to you. So quick wrap up.
When you're using dynamics, focus on what it is precisely that you're really trying to do in small pieces. It really helps to build complex dynamic interactions and animations piece by piece. In fact, we are iterating all the time when we create this. You're going to have different constraints that you want to take into account, duration, interactivity, et cetera.
There's all-- there's a whole other bunch of new animation APIs that we added in iOS 7. Those might be more suitable in many cases. For example, there's an animate with duration API that allows you to implement kind of a simple spring animation as well. So look at those two. And then just go to town, create awesome stuff. All these sessions, I believe have already happened but you can look at them on the videos. They all talk about dynamics. Some of them talk about custom view controller transitions. That's it.
[ Applause ]
Thank you.
[ Applause ]