Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
[ Applause ]
>> 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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ 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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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 ]