[ Music ]
>> Stanford University.
[ Silence ]
>> Okay, well, welcome
to Lecture number 8
of Stanford CS193P, Fall of 2013
and 14, and today, we are going
to talk about a couple of
"objective-C" things first.
Language features,
basically, and then we're going
to talk about animation.
So animation is our topic of the
day, I'll be starting a demo,
at the end, which we'll
finish on Wednesday.
And I'm going to demo pretty
much everything I talk about,
including the objective-C
things, and even including some
of the things we talked about
last week, so it's going
to be a very big,
comprehensive demo,
that's why it runs
over into two things.
So the first objective-C
thing we're going
to talk about is protocols.
I hinted at this
earlier in the quarter.
This is a way that we're going
to make ID a little more useful
by making it a little
safer, okay?
And we already have
introspection to make ID safer.
When we have something that's
an ID, we know it's a point
or do some object, we don't
know what kind of object,
we know how to use introspection
to ask at run time,
"What kind of object are you?"
"What kind of methods
do you respond to?"
That's nice, but it would
be better if, in our code,
we could document in a
way that both the reader
of our code can understand
and also
that the compiler can
understand what it is we intend,
okay, with that ID.
What methods we plan
to call on, on that ID.
And so that's what protocols do.
It's basically syntax, it's
just syntax in the compiler,
nothing more than that.
It's just kind of the same thing
in a string star versus ID,
that's really just
syntax in the compiler,
it makes no difference
at run time.
And the fundamental part of
the syntax is right here,
ID angle bracket protocol obj.
So that's declaring a variables
type "obj" which is an ID,
but it's got this additional
little thing, my protocol,
which tells the compiler
and readers
of your code a little bit more.
So let's talk about protocols
and how this all works.
The first thing we're
going to talk about is how
to declare a protocol.
And declaring a protocol looks
almost exactly the same as an
at sign interface statement.
At sign interface is where
you put all your methods
and properties that are
public, or you can have an
at sign interface at the
top of your implementation
and have private methods and
protocols - or, and properties.
And the same thing for
protocol, with just you say
at sign protocol instead
of at sign interface.
Now, a protocol is just a
declaration of the methods.
There's no implementation,
so there's no
at sign implementation
for an at sign protocol.
We're just talking
about the methods.
And the methods in a protocol by
default are all required, okay,
so that means if
someone wants to say
that they implement
this protocol,
they have to implement
all these methods,
and so those are all the methods
in my little sample
protocol here.
You can make some of
them optional by putting
at sign optional in there.
And now, all the rest
of those are optional,
so now in this example,
some method is required,
but all the rest are optional.
And you can put at
sign required,
again, down a little lower.
Now, all of these are
required except for method
with argument is optional.
Okay? So, we're basically
defining a little pile
of methods, some of
which are required,
and some of which
are optional, okay,
that's what a protocol
declaration is all about.
Now you see how I've added
X-Y-Z-Z-Y and angle brackets
after protocol FOO there?
So what that says is, if
you want to implement,
if you want to say you implement
protocol FOO, you also have
to implement all the required
methods of protocol X-Y-Z-Z-Y.
Whatever that is.
Okay? So it's basically a way
of kind of like super protocol,
it's not really inherent or
anything, but just kind of adds
to the methods that is required
by a protocol, and in fact,
you can have multiple ones,
so here's protocols now
requiring you implement the
X-Y-Z-Z-Y protocol and a
protocol called NSObject.
Okay, now, let's talk about
this NSObject protocol
because it's a very
common protocol.
You're used to the
NSObject class, right?
And NSObject protocol
is basically a protocol
that includes almost all the
methods in the NSObject class.
Okay. And why do we do this?
Why do we have a
protocol named NSObject
and a class named NSObject,
and they have pretty much the
same methods in it, is equal,
is kind of class,
description, perform sector,
all those NSObject things.
The answer is because
we sometimes want
to declare a protocol where
some methods are required,
but we also want to
require the thing
that implements the protocol
to essentially be an NSObject.
Okay. We want it to be an
NSObject, we want to be able
to maybe use introspection,
things like that.
Well, the only way to do that
is to have the protocol have
like a super protocol, you
know, an additional protocol,
and so we just took all
the methods in NSObject,
we put them all in
a big protocol
and have NSObject
implement that protocol.
Okay. So NSObject
protocol and class,
all the same methods
pretty much.
Okay. It's just that NSObject
the class is an actual
implementation of those methods.
So where do these
protocol declaration -
oh yeah, sorry, question?
>> In Java, all class
is automatically inherit
from object, is that not
the case with NSObject here?
>> Yeah, so the question
is, in Java,
all class is pretty much inherit
from object, and that's not true
in objective C, you could have
a class where it just says
at sign interface, name of
class, no colon super class.
In which case, it inherits
no methods from anywhere.
Okay, will only have
its own method.
We never do that, however.
In iOS we always
inherit from NSObject.
Because we want the
introspection
in all these things, but
it's by convention rather
than by some sort of
enforcement for the compiler.
Alright, so these at sign
protocol declarations
of these methods,
where do they go?
They go in header files, they
can go in their own header file,
okay so like have a FOO.H for
my protocol FOO, or they can go
in the header file of some
related class, like some class
that wants somebody to
implement that protocol,
you could put it in there.
So, for example, iOS has
scroll view class, right?
For scrolling.
We're going to talk
about that next week.
It has a protocol called
the UIScrollView delegate,
which is a bunch of will scroll,
did scroll things, methods,
and it's only good for
UIScrollView, so that delegate,
that protocol is defined
in UIScrollView dot H,
not in its own header file.
Okay? So you can kind of
do which ever one you want,
and you'll see them both ways.
Alright, so now we have
the protocol declared,
we defined this little bundle of
methods, including the setters
and getters of properties,
perhaps, now some class has
to promise to implement
that protocol.
And how do you promise
to implement a protocol
if you're a class?
You just put angle brackets,
the name of the protocol,
on your at sign interface line.
Okay? So here, it's my public at
sign interface line, my class,
inherits from NSObject,
angle brackets FOO.
That means my class is promising
to the compiler and to readers
of this code, I'm going
to implement all the
required methods in FOO.
Okay? So I'm just
making that promise.
And you can make the
promise publicly like that,
or you can make the promise
privately by putting it in your
at font sign interface my class
parentheses parentheses thing
that goes in your
implementation, okay,
you can just put it
there if you want.
That's if you only need to
be able to implement that -
you're only required to
implement that protocol
for something that's in your
implementation only, okay,
not on your public thing.
Okay, so now I've got a
protocol, I've got an object,
at least one that signs up
to implement it, now what?
Well, now I can declare
variables that are IDs
with the additional requirement
to implement the required
methods of a protocol.
So ID angle bracket FOO obj,
hopefully, you understand what
that means now, that means
obj is a variable, it's an ID,
I have no idea what class
it is, okay, it's ID,
it's completely blind, however,
I know it implements
all the private
or the required messages in FOO.
Okay? And it might implement
some of the optional ones too,
but I know at least
the required ones.
So if I say ID angle bracket
FOO obj my class alloc - in it,
that looks good because on
the previous slide I just said
that my class promised
to implement FOO.
So the compiler is
going to love that.
But if I said ID FOO
obj NS equals NS array,
that compiler is
not going to like
that because arrays clearly
don't implement a protocol FOO.
They don't implement
those methods.
Okay? So the compiler will
warn you in that case.
Okay, so the compiler here
will warn you if you do this,
it will also warn you if you
sign up to do a protocol,
you promise to do something, and
you don't implement the methods
that are required, it will
warn you about that too, okay,
so it will warn you
both coming and going.
In addition to declaring
variables, like local variables
under the examples there, you
can also pass these around,
these IDs that are
modified by the protocol,
as arguments to methods.
And as properties.
Okay? So, it's really
just another type,
it's not quite an NSString star
where you know exactly the class
and all the methods
exactly that it does,
but it's not quite an ID,
where you know nothing
about it - it's in between.
Right? It's an ID, but
you kind of know some
of the methods in FOO.
Okay? Just like static typing,
this is all just syntactic sugar
in the compiler, makes
absolutely no difference
at run time, no code is
generated any differently
by the compiler because
of these things.
The compiler is just
able to warn you now.
That is the only difference.
Okay? Some people had a little
difficulty accepting this,
but it's true.
No code generation is any
different by the compiler
because of these protocols.
Same thing with NSString
star versus ID.
It's all exactly the same stuff,
gets generated by the compiler.
It's just the compiler
can warn you
because they know
what you intend.
Okay? The number-one
use of protocols
in iOS is delegation
and data sources.
This is back to - remember
Electra 1, I had the MVC
and I told you that the views
could talk to their controller
with blind structured
communication, and we talked
about will do this, did do
that, or the data source,
which is data at count,
that kind of stuff.
All of those, remember
that communication?
This is how we do that.
So it's blind, because
they're IDs,
the views are talking
through IDs.
But it's structured
because there's a protocol
that the view uses to talk
to that object blindly,
so it knows what's in there.
So let's talk about,
for example,
the data source protocols
of views.
If it was a table
view, let's say,
a table view is a generic
view for showing a table
of information, it's protocol
for accessing its data source
is how many rows are there,
and now give me the data at row
7, give me the data at row 500.
Okay? That's its protocol.
Those methods.
Count, and data at,
it has other ones,
but those are the
basic ones, okay?
And we really need those
data source protocols
because views can't
own their data.
That table view can't grab
all its data and display it,
it has to keep asking someone
else, but it doesn't want
to be tied to any
source of the data,
so it wants to be an ID,
it wants to be blind.
Okay? And we'll see
all this next week
when we talk about table views.
There are other uses
of protocols besides
that blind structured
communication, and we're going
to see one today which is
animation, and I'll let
that speak for itself,
but basically we're going
to have IDs out there that are
animatable, and we're going
to know they're animatable
because they're going
to implement a certain protocol,
and that's how we're going
to know that they're animatable
things, and UIView is going
to implement that protocol
and that's how we're going
to animate our views.
Alright, the second
objective-C thing I want to talk
about today is blocks.
Okay, it's a totally
different thing that protocols.
Blocks very important, used
throughout iOS, in fact,
sometimes I have difficulty
getting all the way
to week 5 here or 4 without
putting blocks because it's
so much in the API of iOS.
What is a block?
A block is a block of code.
Okay? Why do we define this
term block, just to mean block
of code, we already know that,
it's because it's a block
of code that can be
embedded inside other code,
passed as an argument,
stored in an array, okay?
So it's a block of
code that we manipulate
and move around our API.
So what does it look like?
Here's an example of a method
that takes a block
as an argument.
Okay? This is the
calling of this method.
There's an NSDictionary
method, it's a real method,
it's called enumerate keys
and objects using block.
Okay? The argument is a block
that has no return value
and takes three arguments,
two of the arguments are IDs,
which are they keys and
values in the dictionary,
and a third one is actually a
BOOL star, a pointer to a BOOL,
it's an outgoing BOOL.
Okay? And basically when
you call this method,
Dictionary will execute that
block of code, repeatedly,
for every key-in value, until
you set the stop, star stop,
to yes, or until it runs
out of keys and values.
Okay? And it's actually
going to implement
that code that's
right there, embedded,
inside that message call.
You can see the open square
bracket for enumerate keys
and objects, before
a dictionary,
the close square bracket is
down after the curly brace.
Okay? So the code, the actual
curly brace, we put right
in there, in the middle
of our message call.
Other languages, in
computer science in general,
we call this a closure.
Okay, how many people
know the name closure,
ever heard that before?
Okay, so you guys generally know
what this is, it's a closure.
Blocks in objective-C always
start with the carrot.
That's the magic
block character.
And then there might be a
return type, possibly specified,
and maybe some arguments,
possibly,
and then a curly brace, and some
code, and an end curly brace.
Now, of course, to make
this really interesting,
the compiler knows how to do
things like have local variables
that are declared
before the block is used,
work inside the block.
Okay? So if I had that block
and I wanted to stop not just
when I see the key enough but
also when I see the value,
stop value, which is a
local variable defined
in the scope that's calling
the method enumerate keys
and obj using block,
I can use it.
The compiler makes
sure that the value
of that gets properly passed in.
However - you have a question?
>> Now is this statically
scoped for using things outside?
>> Uh...yeah, it is the loc -
whatever scope the A dictionary
enumerate keys and objects,
that call, whatever scope
there, that's the scope
in which the variables
can be used,
which is pretty much
the local stack, right?
The stack from your thing, now,
those variables though
are read only.
Okay? So if I had another one,
a BOOL stopped early and I tried
to set that inside my block,
that would be an error,
compiler would not
allow that okay?
Because stopped early
is read only.
However, there's
actually a way to make it
so it's not read only,
which is to put underbar,
underbar, block in front of it.
If you put underbar,
underbar, block in front
of a local variable, then the
compiler will generate code
that transfers stopped early
off the stack into the heap
so that it can be
used by the block,
and then when the
block is finished,
it will copy the
information back into the heap
and then back onto the stack.
Okay? All happens magically.
So if you have underbar,
underbar,
block, it knows to do that.
So that's the magic
you put in there,
and now your variables
can go both ways,
and now stopped early
is yes is legal.
Okay? This also works
if the variable is
an instance variable.
We don't really access instance
variables except for setters
and getters, but that's
because instance variables,
of course, are in the heap.
Because all objects
are stored in the heap.
What about objects that are
messaged inside of a block?
Because there's a little special
thing to think about there.
So if I had a string stop key,
which was enough, and I wanted
to use stop key inside
that block, like this,
I have to make sure - well
not I have to make sure,
the compiler has to make
sure - that it generates code
and the runtime has to make
sure it works, so that stop key,
that there's a strong
pointer to it,
otherwise it could
leave the heap
by the time this block executes.
Because this block could
execute at any time.
Okay? This block happens
to execute immediately,
when you call this, but it's
legal for the dictionary
to grab this block
and store it somewhere
and execute it sometime
later than it wants to.
Okay? So every time you -
listen to this carefully,
every time you send a message
to an object inside a block,
a strong pointer is created
to that object, and it stays
around until the block
goes out of scope,
until the block no
longer exists.
Okay? As long as that block
exists, a strong pointer
to every single object in there
that's message will exist.
Before I talk about that, I want
to talk about some shorthand.
If the block has no
arguments, like this block, see?
No arguments there.
You do not need to put
the parentheses, okay?
You can just leave those off.
And similarly, if the
return value of the block,
so this block which is the
first time you've seen a block
with a return value, it
returns a BOOL, see that BOOL?
If the return value
can be inferred
from the contents
of the block, right?
So in this case, return obj
is kind of class UI class,
definitely going to return
a BOOL, you do not need
to put the BOOL there.
In other words, if
it can be inferred,
it will figure it
out for you, okay?
So just to clean up the syntax,
you don't have to put the BOOL
in there all the
time or whatever.
Okay. Now.
Let's talk about how blocks
sort of act like objects.
Blocks are not objects, okay
they're not, but they sort
of act like objects in the only
in this fine really small way,
which is, they can be stored.
Okay? And they are
reference counted
by the automatic
reference counter.
So storing them means they
can be stored in variables,
in properties, and in
dictionaries and arrays.
Okay? So they can be stored
just like they're objects,
but they don't understand
any messages like an object.
Actually, they understand
one message which is copy,
which is kind of an important
message because that copies them
in the heap, and if you
want to keep a pointer
to a block around, you
probably want to copy it, okay,
so it doesn't just go
off the stack somewhere.
So for example, here I am
putting a block into an array,
so I have a property in my
class my blocks, a mutable array
of blocks, and I just
say self dot my blocks
at object colon a block.
Okay? I know this looks
weird, and it is weird,
because blocks are not objects,
but they act like objects
for this purpose of
storing them in things.
Okay? So pretty neat.
And by the way -
I have not talked
about basically how you
would call this block.
Like if I grab this block
out of this array and wanted
to invoke it, how would I do it?
I'm not going to talk about that
today, but I'm going to show you
so that you can see it.
Really, you're not going to
have to do that in this class,
because you're going to
be passing blocks to iOS
and it's going to be executing
them, but if you wanted to know,
that's the syntax, it's kind
of like C-function syntax,
you can look offline,
I just don't have time
to cover it unfortunately.
But there's a real
danger lurking here.
Okay? In this code, above.
Okay, this self, do
something, thing.
And what is it?
Well, it's called
a memory cycle.
How many people know
what a memory cycle is?
Okay, not very many, that's
good so I'll cover this.
A memory cycle, it's caused
because all the objects inside
that block have a
strong pointer to them,
as long as the block exists.
Okay? So, for example,
in this code, self -
a strong pointer will be
held by that block to self.
You see why?
Because the block, as long as
it stays around in that array,
it needs to be able to
call self do something,
so it needs to always keep
a strong pointer to self,
as long as the block exists.
However, the problem is
that self has a strong
pointer to the block.
Through it's my block array.
Right? Self has a strong pointer
to my block, which is an array,
the array always hold
their things strongly,
so now both of them are
pointing strongly to each other.
The block is pointing to self,
self is pointing to the block.
Neither of them can ever leave
the heap in that situation
because there's always
going to be a strong pointer
to them - each other's - right?
One of them can't
leave first and make it
so there's no pointer
to the other,
because they are
keeping each other in.
That's called a memory cycle.
Okay? And we have to
break these cycles.
Okay? This is a serious problem,
you definitely want to be able
to break these cycles,
and here's how we do it.
We're going to do it
with a local variable.
Okay? Now, local
variables are all what?
They're all strong.
Right? Local variables are
strong, they're strong pointers
into the heap, pointer
variables,
until the method ends, and now
the strong pointer goes away
and so now that local variable
obviously is not holding
something in the
heap by being strong.
But there is a way to actually
create weak local variables,
with underbar, underbar, weak.
Okay? Underbar, underbar,
weak before a local variable
declaration will make
that variable weak, okay?
And remember that weak means
it's not keeping the object
in the heap, if no one
else is pointing to it,
it just goes away, and the
weak variable gets set to nil.
Okay? So I'm going to make
a local variable, weak self,
which points to self, but
is weak pointer to self,
and now I can use that inside
this block that I added.
I'll send do something
to weak self,
and now I don't have
this cycle anymore,
because the block no longer
has a strong pointer to self,
it has a weak pointer.
Okay? So yes, we will do this.
You might have to do
it in your homework,
depending on how you
decide to implement it,
and I will definitely
do it in the demo today
so you can see how this works.
Okay? This is really the
only place we have these kind
of cycles, with ARC, with the
automatic reference counter, um,
it's not too bad, you just have
to know it's there,
and deal with it.
Okay? Okay.
So when do we use blocks in iOS?
We use them for enumeration,
you saw that dictionary,
enumerate, keys and values.
We use it a lot for enumeration.
We use it for view animation,
I'm going to do the whole rest
of this lecture and the start
of next lecture is
going to be about that.
And we use it for sorting.
There's messages you can send
to arrays like sort this array,
and use this block to compare
two objects in the array.
Okay? Notifications.
Right? When a radio
station broadcasts instead
of sending a notification
message,
you can say "just
execute this block"
when broadcast happens
on the radio station.
Error handler is very common.
Do this thing, and
when an error happens,
execute this block
and I'll handle it.
Okay? Completion
handlers also very common.
Do this thing that's going to
take a long time, and it's going
to be done in a background
thread, and when it's done,
execute this block
to let me know.
Okay? Animation does
that, in fact,
we'll see that in animation too.
Question?
>> So you have like a
method defined in your class
and you want to use that
function as a block.
Is there any easy way to
refer to it, or do you have
to like write it as a block?
>> Yeah, so the question
is, if I had a method,
defined in my class or
whatever, and I want to use it
as the contents of the
block, just call self
and that method inside the
block, and that will call it.
That's a common thing
to want to do, actually.
Um, a very, very important use
of blocks, which we're going
to talk about later in the
quarter, is multi-threading.
Okay? Which is getting your
application doing multiple
things at the same time,
not really at the same time,
but seemingly at the same time.
And I really encourage you,
this is one of the few times
I'm going to tell you go look
in the documentation to
find out about blocks,
just search for blocks in X-code
documentation, and you can find
out things like how to declare a
local variable that is a block,
and things like that, because
I haven't really talked
about those things.
Mostly I've just talked to you
enough about blocks to be able
to call methods that
take blocks as arguments.
Okay? That's all I've pretty
much shown you so far.
Okay. So that's it
for the objective-C
that I wanted to cover.
And now we can get into the
fun stuff, which is animation.
Alright? So that's going
to be the rest of today
and probably the
start of Wednesday
because this demo is really big.
And there's lots of different
animation that goes on in iOS.
I'm going to talk today, and
only really in this course,
for the most part,
about animating views.
Okay? You know how to
create custom views, right?
And you can even animate
non-custom views, buttons,
or whatever you want, but
basically making views move
around the screen, get bigger
and smaller, fade in and out,
spin around and rotate, that's
what we're going to talk about.
Okay? Animating views.
But. There's other animation
that goes on, like when you go
into a navigation
controller, and you click,
and a new view slides in, okay?
That's animation.
Alright? And it's
possible, also,
okay you're in the maps app
and you click in the corner
and it curls up to
show you other options?
That's animation, okay?
All that kind of view controller
animation, I'm not going
to talk about, for
the most part.
Okay? But that's all - there's
all support for that as well.
There's also a whole other thing
in iOS called the collection
view, which is a collection
of views that kind of live in
a grid, sort of, or in a flow,
kind of layout, and those
all can be animated.
What's going on in
there as well, okay,
but I'm only going
to talk about views.
Underneath all of that is this
framework called core animation,
super powerful framework,
I mean,
industrial grade animation
framework there, but we're going
to be doing it all at
a much higher level,
much easier to program, and
you know, kind of easier to -
you don't have to know quite
so much about the detail
of how animation really works.
Whereas core animation is
really for animation people
who really want to do
serious animations,
and a lot of iOS applications
are games, or other things
that have a very serious
animation going on in there.
By the way, in iOS 7 there's a
lot of other things we're doing
in animation, for example,
sprite kit is a way
to animate sprites, which are
essentially 2-D graphic elements
that are being composited
in a way to try
to get a 3-D looking
environment,
like a lot of video games
are, and we're not even going
to touch sprite kit,
I don't think,
unless we get to
it the last week.
So there's a lot of stuff
that I can't possibly cover,
so let's just talk the
basics here of animation.
So there's three ways to
animate views, basically.
Okay? The first way is
that there are some very
special properties in view,
namely the view's frame,
remember that's the rectangle
enclosing it, it's transform,
which we talked about briefly,
when we did the playing
card thing,
transform is the view scale, can
be used to scale it up and down,
and it's rotation, views can be
rotated, and also translation,
although usually for
translation we use the frame,
we move the frame around.
And also alpha, it's opacity,
these three things can be
animated at any time into view.
Meaning, you set them to a
new value and it will set
to that new value immediately,
but the effect will appear
on screen animated over
some amount of time.
So, let's take a look
at how this works.
It's done with a class
method in UIView.
Okay? A class method, it's not
an instance method in UIView,
it's a class method, and the
class method basically takes the
animation parameters, how long
to take and stuff like that,
and it takes a block,
and inside that block,
you can modify these
three properties.
There's actually a
few others you can do,
but these are the three
main ones I'm going
to talk about here.
So it looks like this.
It's called animation
with duration,
and the first argument is
how long you want it to take
for this thing to
appear on screen,
remember that the change you
make happens immediately.
So if you change the
alpha or the frame,
or the transform, it
instantly happens.
As soon as this method
is executed.
And this method returns
immediately at all times, okay?
It does what's in the
block immediately.
But the appearance of it is
going to happen over time.
Right? It's going to fade in, if
it's alpha, it's going to move
over if it's the frame,
it's going to rotate
if it's the transformer.
Okay, that's going
to happen over time.
Duration says how long
to take to do that.
Okay? Delay is how long
to wait to start doing it.
And why would you want a delay?
Well becomes sometimes you
want to chain animations,
you want to do one animation
first, that takes two seconds,
then you want to do another
animation after that.
Well, there's two ways to chain.
One is to delay the second
one using this delay,
second argument, or
there's a completion block -
you see the completion
block at the bottom there -
you can actually do
another animation in that.
Because that completion
block is called
when the animation completes.
Alright? Options.
We're going to talk
about all the options,
and quite a few options
for animating.
And then there's the all
important animations argument.
That is a block, you can
see, it takes no arguments
and has no return value.
In that block is
where you change frame
and you can also change center,
center and frame are related,
and transform and alpha.
Okay? So here's an
example of calling it.
So I'm saying UIView class
method, animate with duration,
this animation is going to take
3 seconds, and what I'm going
to do is, whatever
state my view is in,
I'm going to make it
fade out and disappear.
Okay? So, you see in
the animation block?
My view dot alpha equals zero.
That means fully transparent.
Okay? So that is, whatever it's
at now, okay, could be anything,
it's going to go from
whatever it's at now to zero
in three seconds,
on screen, okay?
But in the code, this
happens immediately.
Immediately the view has
gone to alpha of zero,
it's just onscreen it's not
showing what's currently the
state, it's showing
this animation.
Okay? And notice the
completion handler there.
Okay? The argument
to the completion
handler's block is a BOOL
that says whether the
animation finished.
Why wouldn't this
animation finish?
Well, some other animation
might start animating alpha.
Or someone might just set alpha.
So if anyone interferes,
with alpha,
then the completion
handler will get called,
this animation will
get interrupted,
the completion handler
will get called,
but the BOOL there will be no.
But if nothing interrupts it,
and the alpha goes all the way
to zero, then this completion
handler will be called,
and the argument will be
yes, yes it completed,
and if that happens, I'm
then going to remove my view
from the view hierarchy.
So what this single line of code
does is it fades out my view,
and if it successfully
fades it out,
removes it from the
view hierarchy.
Question?
>> Did you, in the next line,
did kind of the same thing
except changed the alpha
to something else?
And you had delay
equals three seconds.
It seems like it's right on the
edge there, maybe it happens
after this one finishes,
or maybe it happens before.
Is there - ?
>> Yeah, so the question is,
what if I have another animation
that I execute on
the very next line.
Well first of all, let's
say I delay this one, right?
So you're saying delay this
first call, put delay in there,
delay equals three or something?
>> Actually delay the second
one, so that it has to -
>> Okay, delay the second
one, exactly three seconds?
Okay, so that will be fine
because the first one will
finish instantly right before
the second one starts, okay?
Because it's a common practice
to do just exactly that.
Have something take
three seconds,
and then start the
other one with a delay
of three seconds,
so yeah, it'll work.
Here's another - oops!
Well I guess I can do
that example, but anyway -
so that is - does everyone
understand what's going
on there?
It's really that simple, the
main thing to understand is
that alpha would be set
immediately to zero,
it's just on screen
that it will show.
Alright, let's talk about
some of the options.
The first one's an
interesting option,
begin from current state.
So if you set this option
on, okay, and when -
in the options list
- what this means is
if there is another
animation that is going
on that is animating the
things I want to animate,
then pick up from wherever they
are when you do my animation.
Okay? So if I'm doing that
alpha thing and it's fading down
and it's down to
0.2, or something,
and then I issue another
animation to start,
that goes up to 0.7 alpha,
if I begin from current state
option on, then it will start
at 0.2 and go up to 0.7.
If I don't have this on,
it will start at zero,
because zero is what the real
alpha is, and go up to 0.7.
So begin from current
state is a way
of intercepting other
animations,
intercepting them, right?
In mid-flight.
Okay? You need this
because remember
that when you set these
animation parameters,
it happens immediately.
So if you want to
intercept animation
in flight you need some option
for the system to go check
and see where the view is,
if it's flying across screen,
before it sends it to a new
place or if it's fading out,
it fades at its new level.
It's very common to have
that option on, actually.
And then you see things
like allow user interaction,
do you want to allow
gestures to happen
in this view while
it's in flight?
Sometimes that makes
sense, sometimes not.
Down at the bottom,
you see those curves?
Curve ease in, curve ease out?
Sometimes when you move a view
across screen you don't want it
to just up and move, you want it
to kind of slowly pick up speed,
get up to full speed, and
then slow down at the end.
It's a little smoother
kind of animation
than just here's my view,
mmmmm, that's a little, mmmmmm,
you know, but mmmmmmmmmmmmm,
okay?
Better. Smoother.
So curve in, ease and out,
that's for controlling that.
Okay? Same thing for fading, you
could do it for fading as well.
Though fading tends
to be okay linear.
But moving definitely curving in
and out is a pretty good idea.
So you can look in
the documentation
and see what all these options
do, you can repeat animations,
have them go over and
over and things like that.
So that's how you animate
those special properties, okay?
And it animates them, it
figures out all the in between.
Even if you animate multiple
of them at the same time.
It's moving, it's fading,
it's rotating, it will find,
you know, it will interpolate
all those points all the way
along automatically.
Okay? And pretty high
performance, as well.
Okay. Sometimes though,
you're changing your contents
of your view in a way that's
other than those three things.
The classic example
here, the playing card.
When I'm flipping my
playing card over,
the only property I'm setting
in my view is face
up equals yes, right?
And now my card flips
over to face up.
Face up equals no, now
it flips over to down.
So that's not an animatable
property per se, however,
what I'd like to do is have the
view change from face up to face
down through some animation,
like flipping the card over,
or dissolving between the two.
In other words, I want
to change the entire view
through some animation
to a new state.
And that's what this one is for.
Transition with view.
So transition with view takes
a view that you want to do,
like a playing card view,
and it takes a duration.
How long it's going
to take to go
from the old state
to the new state.
Options, again, similar
to the other options,
but this is especially where you
would specify the options listed
at the top there, like UIView
animation options transition
flip form left would mean
I want this to flip over
or cross dissolve, or curl up.
And animations, again,
is a block,
that's where you're
going to set face up.
In that block, you can set
anything you want about the view
to make it be in its new state,
and the system will apply all
those changes, re-draw the view
in the new state, off screen,
and then transition
between the two.
The old state is on screen now,
and whatever your
changes result in.
Make sense?
Questions about that?
And then completion, same thing,
if you get interrupted somehow,
you know, it's harder to
get interrupted on this one,
but it can happen, then the
completion handler gets called.
Either way.
Okay? So this one will be great.
Part of your homework is
to flip that card over,
and this is the method
you're going to want to use,
so very, very straightforward.
If you're changing
the view hierarchy,
like you're swapping
a view out, okay?
You got a view in
the view hierarchy
and you're swapping a new
one in, or if you want
to hide a view in
favor of another view,
you can use this
transition from view to view.
So this one is kind
of like the other one
in that you're changing, but
instead of having a single view
that you're changing its state
and then flipping it over,
here you're replacing a
view with another view.
Okay? But otherwise
is very similar.
It's even called almost the
same thing, transition, right?
Transition from view to view.
Okay? Alright.
So that's it for direct
changing of views, properties,
and making things happen.
Okay? The next kind of animation
we're going to talk about,
which is a totally different
system, new for iOS 7,
is called dynamic animation.
And this one's a
completely different concept.
Here, what you're going to do,
is define a bunch of physics
that apply to all the views
that you want to animate,
and then you're just going
to say "Okay, do it!"
And they're going to go have
those physics apply to them.
So what kind of physics
are we talking about here?
We're talking about gravity,
collisions, forces applied
to them, things like that.
Okay? And they're just
going to keep on animating
until the forces
all balance out.
Okay? And we'll see
what that looks like.
The way we do this, this
is a really nice API,
very easy to use.
You create a UI dynamic
animator,
you just need to create one.
You can do multiple,
but just one -
it's really for grouping
these behaviors,
but usually create
one dynamic animator
with alloc in it, basically.
I'll show you that.
And then you're going
to add behaviors to it.
Behaviors are like
gravity, collisions, pushes,
those kinds of things,
those are behaviors.
Things that are going to
be applied to the things.
And then you put the things in
there, and the things you put
in there are UI dynamic
items, meaning they respond
or they implement that protocol.
I'll show you that.
And the instant you put them in
there, they'll start animating.
You don't have to say run, you
don't have to say anything,
immediately, any time there's an
item that's in a behavior that's
in a dynamic animator, it will
start animating until the forces
on it, meaning that it doesn't
need to move, then it will stop.
Okay? So let's look
at all these things.
UI dynamic animator, you
can just do alloc init,
but when you're doing views,
if it's views that you want
to animate, if you want to do
alloc init with reference view.
Okay? And init with
reference view,
you're specifying the top
view of a view hierarchy,
all the views you animate have
to be in that view hierarchy,
in other words, they
have to be somewhere,
a subview of this reference
view or a subview of that
or a subview of that, as deep
as you want to go, but you have
to specify the top level view.
Okay? Then you create
these behaviors.
Behaviors are just alloc init,
like UIGravityBehaviorAllocInit.
UICollisionBehaviorAllocInit,
and then you add these behaviors
to the animator,
using add behavior,
which is a dynamic
animator method.
Okay? Couldn't be simpler.
And then, you add the
items to the behaviors.
And you do that with?
Add item, in dynamic behavior.
So an item is just an ID
that implements the
protocol UIDynamicItem
which you can see there below.
And again, UIView
implements that protocol,
so usually the items we
put in there are UIViews,
about 90 percent of the time.
100 percent of the time in this
class, 100 percent of the time
in your homework, I'm only
asking you to animate views,
but you could animate
completely non-visual items.
They could be - as long as
they implement this protocol,
they can do anything they want.
So what's in the protocol?
There's the bounds.
That's again the bounds
in the items world.
It's like the views
bounds, right?
It's its own drawing
coordinate system.
Notice that's read only.
Okay? It could be modified
by the transform, centering,
moving the thing around,
possibly, mostly the transform.
So the bounds, though, is just
the drawing area for the item.
But the center, in other words,
the position of the item,
and its transform, it's rotation
and scale, those are read-write.
Those can actually be set.
They're obviously
set by the animator,
that's what the dynamic
animator does is go figure
out what the center and
rotation and scale should be.
And you could set them too,
but if you do set them while the
animator is also setting them,
you have to call this method
update item using current state,
current state in the animator,
otherwise the animator
will not -
will ignore anything
that's going on.
Okay? So if you want to
be setting the center,
if you want to be moving the
thing while the animator is also
trying to move it,
in other words,
you want to fight it a little
bit, or if it is moving it
and you want to rotate it,
you need to do this update
item using current state,
otherwise it will assume,
for performance reasons,
that it knows the current state.
Until it's done animating,
until everything settles.
Okay? So that's it.
Animator, behaviors and items.
That's all there
is in this system.
So now let's talk about
some of these behaviors.
The concrete behaviors
that are available.
There's gravity.
Okay? Gravity - gravity behavior
by default, gravity is down.
So if I'm holding my phone, it's
down, which kind of makes sense
if I hold my phone up I kind
of want things to go down,
but really it can
be set to any angle.
You can have the gravity
up or to the left,
you can have multiple
gravity pulling on things
from different directions.
In fact, if you had two things
pulling, one from the top,
one from the bottom, the thing
would just float in the middle
if they have the same
magnitude of gravity.
And you can set the gravity.
Magnitude of 1 means a thousand
points per second squared.
That's the acceleration
due to gravity.
That feels a lot like 9.8
meters per second squared
which is acceleration
due to real gravity.
So in other words, if
you hold your phone up
and let the gravity work, it
kind of feels like it's falling
about the same speed, something
in real life would happen,
and it's also a very
nice round number,
a thousand points
per second squared.
Okay? But understand,
it's just like gravity,
it's an acceleration
in a certain direction.
Collision is really cool.
Collision just means
the items inside
of the collision behavior,
if they bump into each other,
they'll bounce off each other,
like a real world collision,
and you can specify
the elasticity
and how bouncy they are, and
even you can define the density
of one versus another,
so a really dense one
will smash another one
out of the way, all definable.
You can also set boundaries.
So any UI [inaudible] path
that you want to come up with,
you can put it in your
collision behavior
and things will bounce off it.
So it can be round, it
can be square, whatever,
and things will bounce
off it when they hit it.
Also you can set the
boundaries of the reference view
to be bouncy boundaries as
well by saying translate
to reference bounds into
boundary equals yes,
and then things will bounce off
the edges of the reference view,
the top level view in
the dynamic animator.
Okay? So, the collision mode
determines whether the items
bounce off each other or
just off the boundaries.
Okay? Alright?
Attachment behaviors.
Okay, this is the
way to attach an item
to a fixed point
or to another item.
Now one thing to remember
about this, if I hook an item
up to a point, that
does not mean
that item is not going to move.
Okay? If I hook it up to this
point and I have an item here,
right, and gravity happens?
My item is going to go like
this...it's going to swing.
Because the attachment is
just attaching the two things,
the point and the item.
It's not attaching to
the background, okay?
And also if I move the point,
the thing will stay with it
and it will kind of
swing around behind it.
And we'll see this
in the demo, okay?
So attachment is attaching
the thing to a point.
You can also attach two items.
If I attach two items like
this and I gravity down,
they're going to go bam!
They'll stay the same distance
apart, but they're just going
to go straight down because
gravity will still be applying
to them as well.
Right? And the connection
just keeps them together.
The attachment behavior
is a little different
in that you don't alloc init,
you actually specify the
attachment at init time.
So alloc init with item,
alloc init with other item,
there's also some versions
where you can attach items,
with the attachment
point instead
of being the center is offset.
And that will make things kind
of hang if the items rotate,
they'll kind of tilt, okay
because you're not grabbing them
in the middle, you're
grabbing them on the side,
so you can make some
pretty cool effects.
The other thing to notice about
attachments that's cool is
that the length between
the two items is writeable.
So for example, let's
say you were pinching.
You could change the length
and those two attached items
would move closer together.
Okay? So even though you set
it up as this item attach
from this point or these
items attach to each other,
if you change the
length to be smaller,
they'll move toward each other,
okay, that which is cool,
and the same thing
with the anchor point.
If you move the anchor
point around,
the attachment is still there
and the thing will
follow around, right?
With other behaviors
applying to it.
Question?
>> Is that attachment length,
is that an exact value,
like it would be with like
when they're attached or?
>> Iron, like an
iron bar you mean?
>> Yeah, like iron
bar or straight?
>> Okay, so the question
is, is it like an iron bar
or is it more like a string?
And actually what it is,
it's like a spring, okay?
So it actually as
you move it around,
like if I move it
up, it will "whoom!"
spring up.
And you can control the
damping and oscillation of that.
By default, it's an iron bar.
Okay? So the damping
and oscillation are set
so that it does not
oscillate, but you can set it
so as you follow it around it
kind of - it's very, very cool.
So you can play with
all of those
when you are doing
your homework.
Snap behavior snaps an item to
a location, but it does more
than just have it fly there.
It does fly there, rather
rapidly I might add.
When it gets there,
though, you can imagine
that there's four springs
attached to the item
in the corners, a little ways
out, so the thing gets there
and it goes "doinggg" -
kind of springs - like this.
And you can specify
how much it does that.
Why does it do that?
That's because you want to
give feedback to the user,
oh, I just moved this.
So you don't want it
to just go "blip!"
You want it to go
"hmmmm," you know,
and it kind of gives them
just a moment's springiness,
so it's like "oh, okay"
and that's good animation,
the snap behavior very common.
Also you have push behavior,
which is you can push,
push an object and
it will start moving.
So especially if you
don't have gravity,
this might be what causes
things to move, you push it
and it moves across and then
these items have friction,
they have density when they
collide with each other,
so push - you can
read about push -
and how you specify the angle
and the magnitude and all that.
Okay? So. Another thing about
behaviors is you want to be able
to set this friction,
elasticity, the density,
all these things that
we're talking about,
you want to set them on
the items independent
of the other behaviors, okay?
So if I have friction,
I want it to apply,
whether it's gravity that's
causing the thing to move,
or whether a collision
caused it to move.
So we don't put the friction and
the density and stuff like that
in collision behaviors
or gravity behaviors,
we put it in its own behavior
called the items behavior.
So there's a class of behavior
called UI Dynamic Item Behavior.
Okay? And so if you want
any of these things,
like you don't want
to allow it to rotate,
you don't want the view
to be able to rotate,
which I don't know if you're
doing homework sometimes you
might want that, sometimes not,
or you want to specify the
friction or the bounciness
of this object, you create
a UI Dynamic Item Behavior
and add the items
to that as well.
So the item would be a member
of the gravity behavior,
it might be of the collision
behavior, and it's also a member
of a UI Dynamic Item Behavior.
Okay? And this controls
all its options.
So you can think of this as kind
of like the animation options,
but really it's more like
the behavior of the -
the intrinsic behavior
- of that item.
Okay? What is its density?
You want that to be the same no
matter what behavior is acting
on it.
You can also find out
information about what's going
on with the item using
UI Dynamic Item Behavior.
It has methods like
linear velocity for item.
It will tell you the
velocity of this item
in different directions.
Which is really cool for if you
want to take over animation,
the dynamic animation system
started this thing moving,
and now you want to take
over and keep it moving,
maybe in some other direction
or something like that.
You can find out how fast
is it moving right now,
and then continue having
it move at that speed.
Same thing with angular
velocity.
How fast it's rotating
in radians per second.
Okay? Dynamic behaviors also -
the UI Dynamic Behavior is the
base class for gravity behavior,
collision behavior, all these,
you can also create
your own subclass,
and usually when you
do your implementation,
just adds other behaviors
as child behaviors.
So there's a method
in UI Dynamic Behavior
called Add Child Behavior,
and you can add a
gravity, collision,
UI Dynamic Item behavior,
as sub-behaviors.
And this is very common to
do, just to clean up your API,
to group behaviors that go
together, into their own class.
Okay? Their own UI
Dynamic Behavior subclass,
and all that thing usually
has is child behaviors
and then maybe a little
bit of API to add the items
in a certain way or have them
interrelate in some other way.
Okay? What is more,
all behaviors,
all UI Dynamic Behaviors,
gravity, collision,
your own custom ones, whatever,
they know what dynamic
animator they are in.
They have a property
called Dynamic Animator
which will say what
dynamic animator they're in,
and there's kind of a view
controller life cycle thing
of UI Dynamic Behaviors, which
only has one method in it,
will move to animator.
So that gets called every time
it gets moved to an animator
or out of an animator.
So this would be
called with nil.
Okay? So that way you can find
out whether your behavior is
currently being animated or not,
and by which animator.
Okay? And the last thing
I'm going to tell you
about behaviors, really cool
property is a block called
action, this block
returns nothing
and takes no arguments,
so it's basic block.
This block you provide, you
just say my whatever behavior,
gravity behavior,
collision behavior, whatever,
dot action equals a
block - it will execute
that block every time
this behavior causes
animation change.
Okay? So this is called a lot,
as gravity pulls the thing down,
every time it moves, even a
pixel, this thing gets called.
Okay? If a collision happens,
and it moves that causes it
to move, this will get called.
Okay? So this is a way to get
in there and get involved.
Now, you have a responsibility
when you get in there,
don't do anything really
expensive in action
or your animation
will get all jerky.
Okay? You do not want to
do something expensive
like draw too much, but
you can draw a little bit.
And we'll show in the demo on
Wednesday, we'll get to the part
where I'll set an action
that draws a little bit,
so that we can see
things a little better,
and you can see this, really
nice to be able to set this.
Okay? So this is a simple
little hook to get involved
with the animation that these
behaviors are causing to happen.
Okay?
Alright. So let's do this demo.
All that what to look for,
you can look on later,
just to make sure you
actually saw this.
This demo is called "Drop It."
And basically going to
drop views, squares, down,
and they're going to
collect at the bottom,
and when a whole row collects,
I'm going to blow them up.
Kind of like Tetris.
You know Tetris?
You put the blocks in and when
they fit and you get a row,
boom, the row disappears.
We're going to do that.
Okay? We're not going to
use Tetris squares and stuff
like that, this is a demo, I
only have like 45 minutes to do,
but we'll do blocks instead.
But the main thing I just want
to show you everything I can
in that amount of
time, about animation.
So we're going to make a new
app here, let's get rid of that.
Don't need that.
We're going to create
a new project.
I'm going to call this project
- I'm going to go quite fast now
through most of this stuff that
you already know how to do.
So I'm going to do Drop It,
I'm going to call the view
controller also Drop It.
Okay? We'll put it in
home directory developer.
Here's our Drop It.
You know me, I always like
to move these out of the way.
Alright. So here's
my storyboard.
I'm going to use a generic
UIView to contain my game.
Okay? My little dropping game.
I could do all this dropping
in self dot view here,
but it's usually a bad idea,
because what if I ever want
to add a score or another
button or something like that,
I want my game then to be
in a little smaller space,
and you're going to want to do
that for your homework as well.
So I'm just going to drag
out a generic UIView.
I always have trouble
finding it.
Yep, there it is.
So I'm just going to drag
this generic UIView in here,
and I'm going to
create an outlet to it,
I'm going to call
it my game view.
So just control, drag, out
here and call it game view.
And it's a generic UIView.
It's no custom thing.
But I just want it
to be the bounds,
and I can move these bounds
in from the edge if I wanted
to put some other UI
in there or whatever.
So now I have my game view.
And I'm also going to
have a tap gesture,
so let's drag out a tap gesture.
So that every time
I tap on this,
I'm going to add
another square to drop.
Okay? So I'm going to
put this on my game view.
Here's my tap gesture
right here.
Control drag this
out, I'll call it tap.
Okay. Get some more
space here for us.
So every time that you
tap on my game view,
I'm going to drop another, drop
another full square that falls
down like a Tetris
kind of thing.
Oops. Oops.
Drop. Okay?
So that's what this
method is going to do,
it's just going to add a view.
So this is also a chance
for me to show you how
to create a UIView in code,
which hopefully you've all done
that because you've
done the part
of the homework that's
the custom view,
but if you haven't, here you go.
I'm going to actually
create the frame first.
I'm going to have the
frame origin start
out at CG point zero,
but then I'm going
to change the X origin.
So I'm going to have that
drop start out at the top
and then I'm just going
to put in a random spot
across the X. The size, I'm
going to define a nice little,
well let's do a static.
Static, const, CG size, we'll
call this drop size equals
and I'll make it like
40 by 40, but I'm going
to make this be static
const as opposed
to it making it be a property or
something because I don't want
to write the code right
now to deal with the fact
that someone changes this,
because I probably have
to re-draw my whole thing to
have smaller squares, right?
Or something like that.
Which is cool, be great to do,
but just with time constraints
I'm not going to do that.
So I'm going to have the
frame size be this drop size.
So I'm creating a
little drop view, okay,
and that's the size
I want it to be.
So here I'll do my random
- actually let's go ahead
and do this...let's go to here.
Let's go just pick a random
place along the X axis,
so I'm going to do arc 4
random, and we're going to mod
that by the self dot game view
dot found dot size dot width,
so somewhere along some
random spot along there.
And I'm also going
to make it be lined
up so the drops are,
you know, in a grid.
So I'm just going to divide
by the drop size dot width,
and then I'm going to
multiply by saying - oops,
frame dot origin dot X equals X
times the drop size dot width,
so you see here, I've divided
it here, this is an int,
so it's basically going
to do a floor, right?
I've picked an int and just
multiply it back, that puts it
at a random spot across, and
then I create a view just
by saying drop view equals
UIView alloc init with frame,
which is the designated
initializer for view,
and I'll specify this frame,
and then I'm just going -
I'm going to set the drop
views background color
to be a random color.
Okay, I happen to have a little
snippet for that, random color.
Okay, so random color
just picks one
of five random colors,
okay, right here.
And then let's just go ahead
and self that game view,
add sub-view, drop view.
Okay? So it's as simple as
that to drop something on here,
so unless I've forgotten
something
or doing something wrong,
let's go ahead and run.
Every time I tap, we get
another one, so that's great.
They're collecting at the top.
Now we're going to add some
gravity so that they fall down.
Okay? Animated, so
they fall down.
So how do we do that?
Very simple, we're just
going to create an animator,
have a property which
is strong non-atomic,
which is a UI dynamic
animator, and I'm also going
to have a property which
is strong, non-atomic,
which is a gravity behavior,
I'll call it gravity.
Keeping these names short
kind of for a reason,
but you might want to
call it gravity behavior.
I'm going to go ahead and do
some lazy instantiation here,
so let's get our dynamic
animator, if not animator,
then I want to create one,
otherwise I'm going
to return it.
Okay? So as I said when
we create the animator,
it's just UI dynamic animator
alloc init with reference view
and the reference view is
just our game view, right?
That game view that I dragged
out, that generic view,
it's perfectly fine
for that reference view
to be a generic view.
And then the gravity one
similar kind of deal,
if the gravity is not
set, then we'll create it
and we'll return it,
and creating a gravity
thing is very simple,
we just say gravity equals UI
gravity behavior alloc init.
Okay? I'm going to do one
other thing here, or two,
I'm going to say self dot
animator add behavior.
Okay? So any time someone
asks me for the gravity thing,
I'm going to add
it to my animator.
This is going to only
happen once, right?
Because this is my lazy
instantiator, so that's good,
that's exactly what I want.
I could also in here set things
like the gravity's
magnitude, right?
So I could say light
gravity instead of 1.0,
a little lighter or whatever.
Okay? So now I have an animator,
I have a gravity behavior,
all I need to do now is add this
drop view, okay, that I created
to that, so I'm just going
to say self dot gravity
add item, my drop view.
Okay? So now that
the instant I do
that it's going to
start animating.
So let's take a look at that.
So you can see as I click they
immediately start animating.
Okay? And um...sorry,
but they're falling
off the bottom, okay?
So that's not so good, I want
them to stop at the bottom.
So to do that, I just need a
collision behavior, very easy,
just go up here, properties,
strong, non-atomic,
UI collision behavior,
collider, I'm going to call it.
And my collider, if my collider
is not set, then I'll set it,
turn the collider, I
really should have a snippet
for that kind of thing.
I think Johan showed that
in the Friday section.
So that equals UI collision
behavior alloc init,
and here I'm also going to
set the bounds, oops, to yes.
So I'm going to have this
collider use the bounds
of the reference view
as its bounds, okay,
so it's a one line thing to get
that in there, but I could make,
you know, a nice UI
[inaudible] path, you know,
like down along the
bottom, whatever I want,
but it suits my purposes
here just
to use the whole
translation, and I'm going
to do the same thing here,
self dot animator add
behavior, this collider.
Okay, so it gets
added to the animator.
So again, I need to add any
items that I want to be affected
by the collider to the collider,
and now it's going to -
as soon as I do that,
if something hit it,
it would start colliding.
Alright? So let's
take a look at that.
Okay, so hopefully the drop,
notice they have a little bounce
to them, a little
bounce in their step.
Okay. Now notice that
they tilt a little.
Why does that happen?
Well, on the way down, the two
they landed, one was bouncing
and the next one hit it,
and there was a little bit
of real world bounce to it.
Now, probably if we're
building a Tetris game,
we don't want them to rotate
and get off center like that,
so we would have to A, not
allow rotation probably and B,
we might want to grid them up.
I don't think we're going
to get that in the demo,
but maybe on Wednesday
I'll get to that,
I'll post how you
would actually do that.
Okay? And all we're going
to do is when they collide,
we're going to have
them line themselves up.
Okay? So we'll do that
later on Wednesday.
Okay, notice that I have these
two very related behaviors,
gravity and collider.
They really go together.
Okay? So this is
where I might want
to create a custom UI behavior.
So let's do that real quick.
I'm just going to go file,
new file, okay, new class,
and this class is going to
be a UI dynamic behavior.
Behavior. And I'm going to
call it the drop it behavior.
Okay? And that is going to be a
new behavior I'm creating that's
going to have the
gravity and the collider
and eventually some more
things as child behaviors.
Okay? So let's hit next,
where we want to put it,
this is all good, here it is.
Okay? Here's my drop it
behavior, and all I'm going
to do in this drop it behavior
is I'm going to define a couple
of methods here, add
item, which allows you
to add UI dynamic item, notice
I'm using this protocol syntax,
and then I'm also going
to let you remove an item.
Okay? And that's all
I'm going to implement
in my drop it behavior except
I'm going to override its init.
Okay, so what am I
going to do in its init?
So instance type, init,
I'm going to do self
equals super init,
so that's UI dynamic
behavior init.
Alright? And then return self,
and then in between
here all I'm going
to do is add child behaviors for
the gravity and the collider,
which I'm actually
going to copy and paste.
Save ourselves a little time,
here's nice little lazy
instantiation of these,
and let's go grab the - oops,
let's grab the outlets
for these, add those.
Oops, sorry, I keep
clicking on the wrong button.
Okay, so this is at sign
interface, drop it behavior,
oops, paste, hello, paste.
And okay so we've got
those, that's good.
These lines, we're not going
to add it to the animator
because we're going to add this
whole behavior to the animator,
so we can get rid of those.
And in add item, which
we'll put right here.
Actually let's go ahead and copy
and paste these two
things that we want.
Add item and remove item.
Okay, all I need to do
here is add them to each
of my sub behaviors, so I'll
do add item to my gravity
and add item to my collider.
And I'll do the same
thing for remove.
Okay, except we want
this to be remove.
Okay. So this s a common
pattern here, you know,
you create basically
a dynamic behavior
that has child behaviors
and in the add,
I mean you also have add items,
you might have init with items,
whatever, and then here, we're
going to add child behaviors,
the gravity and the collider.
Okay? So we've created a new
class here, it's a sub-class
of UI dynamic behavior.
We can add items to it,
just like we added items
to our gravity and our collider,
and its implementation is merely
to have a sub, these
little sub behaviors.
Okay? Very, very simple.
And we go back to our
controller here, we need to,
instead of having the individual
ones, now we're just going
to have a drop it - sorry, pound
sign import, drop it behavior.
It's going to have a
drop it behavior, okay,
we'll put a little
lazy instantiation
for this one too
[typing sounds].
Oops, so there's alloc
init, that's going to call
that other init that
we just did.
We'll do self dot animator add
behavior or drop it behavior,
alright, and then we'll just
return our drop it behavior
like that.
And now, down here, we don't
have to add these separately,
we're just going to say drop
it behavior add item like that.
Okay? So everyone understand
how we kind of grouped all
that stuff over there?
And we're going to add more
things as this demo goes
on to this kind of general drop
it behavior, and we're going
to add them over in
that other class now.
We're still going to add other
behaviors that we add here,
that really aren't part
of that other thing,
but now we collected that
into a nice space over there.
So hopefully that didn't break
anything, let's see, it didn't.
Okay, it's all still
working, which is awesome.
Okay so now what I want to
do is, when I get a full row
like that, I want
it to blow up, okay?
And I'm going to do the blow up
not using a dynamic animator.
Okay? I'm going to do that with
that UI view animation business.
Because I want to show you how
you can mix the two together
and they'll work fine, okay?
So let's do that.
So how are we going to do that?
Well, one question is
when can I start thinking
about doing other animation
when I've got this
dynamic animator going off
and doing all these
things bouncing
and colliding and
all this stuff.
The answer is you can find
out when an animator
reaches quiescent state,
when nothing is bouncing,
everything is resolved.
Okay? When everything is quiet.
Okay? And you do that using
a delegate for the animator.
So if I go to animator
here, there is a property
on animator called delegate.
And the delegate is an
object that's going to find
out when the animator stops
and when it starts up again.
And I'm going to
set that to be self.
Now when I do that, I'm
going to get a warning
from the compiler here.
Why is that?
It says "You are
assigning self,"
which is a drop it
view controller,
"to something that's supposed
to be an ID UI dynamic animator
delegate" - in other words,
you're supposed
to be implementing this
UI animator delegate.
So we have to go up here and say
that we implement this UI
dynamic animator delegate.
This is what we're talking
about, protocols saying
that we promised
to do something.
Okay? Now, I'm not
getting any more warnings,
so there must not be any
required methods in this,
they must all be optional.
And in fact they are all
optional, and there's only two
of them, and the one I want
is called dynamic animator did
pause, you can see there's the
two dynamic animator delegate
methods, dynamic
animator did pause,
and dynamic animator
will resume.
Okay, so that's telling you
when it reaches a settle state
and when something changed, a
behavior or an item got added,
and now it's going
back active again.
Okay? So in this case, we
want to know the pause.
Okay? When the pause
happens, I'm going to look
at that bottom row and
see if it's complete.
Actually I'm going to look
at all the rows and see
if any of them are complete.
Okay? And if they are, I'm going
to blast them out of there.
So I'm going to do that by
calling a method called remove
completed rows, and I
have a little snippet
for that to speed us up here.
Okay. Here it is right here.
Okay? I didn't put
it all in here.
Actually remove completed
row, I call it,
but really should be rows.
And so how does this work?
Well, you can take my word for
it that this little snippet
of code, and you can
go look at it later,
it basically just fills this
mutable array, drops to remove
with all the drops that
are in a completed row,
even if there's multiple
rows, okay?
It does this using
this method hit test.
I'm actually looking at
all these things and seeing
if there's a view there,
and if it is, I'm okay.
And if I get all the way
across a row I'm like, okay,
I've got a whole row
and I'll keep them all.
So that's what drops to remove.
This code right here is
going to fill in drops
to remove with all the things.
Okay, so now we have
an array of the drops
that we want to remove.
Now, let's talk about what
we're trying to learn here,
which is animation,
how do I remove them?
And what I'm going
to do, to do that,
it's kind of a two-part deal
here, the first thing I'm going
to say if I have any drops to
remove, okay, then I am going
to remove all of the drops
that I'm going to be taking
out of this view
from the animator,
from the dynamic animator,
because I don't want the
dynamic animator fighting me.
Okay? I'm going to remove these
things using UIView animation,
I don't want it trying to pull
them back or the gravity pulling
on it, so I'm going to take
them out, and I'm going to do
that very simply by just saying
self dot drop it behavior,
remove item, drop.
Okay? So I'm going through
all the drops to remove,
and I'm removing them
from my drop it behavior.
Now they're not in any
behavior, so they're not going
to be affected by the animator.
Okay? Now, I'm going
to - so that's that.
Now I'm going to animate
the blowing them up.
Okay? And let me do that
with animate, removing,
drops, drops to remove.
Okay? So this is a new
method that we're going
to write together here,
animate, removing drops,
it takes an array
of drops to remove,
okay and how are we
going to do this?
Well, I'm just going to do
UIView, animate with duration.
Okay? So I want - there's
a few versions of this,
some of them have delay,
some don't have delay,
so I want the one -
which one do I want?
I think I want the one with just
completion, so that's this one.
Okay? So I want this
one right here.
How long is this going to take?
I'm going to take about a
second to blow those things up.
This probably wants to be
a constant, and you want
to tweak it to look good, right?
If it blows up too slowly
it looks ridiculous,
if it blows up too
fast, people can't tell
that it did it, so
we'll do that.
And then here's the animations,
which is just a block,
and here's the completion, which
I'm not going to do anything
on complete - actually I
am going to do something
on completion, let's
do something
on completion just to show here.
So finished, okay?
And that's it.
So that's this entire
animate with duration,
all we need to do is fill
in these two blocks, right?
So let's do this block first.
This is the animations.
This is the actual moving.
So all I need to do here is move
these things out of the way.
So I'm going to have
them kind of explode up
and off the top of my view.
So I'm going to move each one
to a random location somewhere
off screen above my view, okay,
kind of just out
there somewhere.
And so how am I going to do
that, by saying 4, UIView,
drop in, drops to remove,
I'm going to have the X be
some random location that is
between two times
my width to the left
to two times above my width.
So it's going to be kind of
going out like this in a funnel.
Okay? So the X has to be from
two times my width to the left
to two times my width on the
right, so I'm going to make
that be self dot game view dot
bounds dot size dot width times
five, okay, so that's
going to get me there,
minus self dot game view dot
bounds dot size dot width
times two.
Okay. And actually I'm going
to move this all back here
so we can see it better,
move this back too.
Okay. So let's do that, okay, so
you see I'm just going five wide
and I'm shifting it over too.
So I'm just creating
this thing above.
And then the Y, I'm going to
make Y easy, I'm just going
to have it be self dot game view
dot bounds dot size dot height,
and then when I move it there,
I'm going to make it negative,
so I'm going to say drop dot
center equals CG point X com
minus Y. Alright?
So inside this duration
block, if I change the center,
it's one of the magic things.
This will get animated.
Okay? Center, and frame,
and alpha, and transform,
those are all the magic things
that automatically will animate,
and what did I type wrong here?
>> [ Inaudible Comment ]
>> Oh [inaudible]
point make, yeah.
Make. Good job.
Okay, so that's it.
So now they're all
going to blow up.
What am I going to
do on completion?
Well, after they blow up, if
they successfully blow up,
I'm going to remove them all
from the super view, right?
Because I don't want
them anymore,
I just blew them
up, they're gone.
So what's a cool way to do that?
Watch this.
Let's go drops to remove,
make objects perform selector,
at sign selector,
remove from super view.
Okay, I told you that
methods like this would come
in familiar, come in
handy, and they are,
it's better than having to do
4, in, you know, all that stuff.
Boom, just do this, it's
going to send remove
from super view to all of them.
Okay? Make sense?
Alright, let's see
if this works.
Alright, so let's add
some of these guys
until we get a whole row,
almost there, almost there.
Oh, come on, oh, there it is!
Okay, now, two things there.
Notice that we got the animation
of the thing happening,
but what happened to
all the other blocks?
They moved down,
because they're all still
under the influence
of the animator.
Gravity is still
pulling on them,
the collider is still working.
So if I put a whole bunch
of things in here, okay,
and also okay they're kind
of tilting, watch this again.
Oop...
>> [ Inaudible Comment ]
>> Yeah, I did.
I did get unlucky with
the hit test there,
here let me show
you a different way.
The hit test is kind
of a questionable way
to do that, by the way.
But, here, let's show you.
I'll just show you this again.
Also, I should make it so that
they're not tilting like that.
We'll do that next time.
But...wow, I'm getting
- oh there we go.
Okay. Hello.
Knock, knock, knock.
Well, I don't know why it's not
working now, but anyway you got
to see it work and time's
up, but we'll look at that,
we'll look at that
later and try and find
out what our problem was.
But anyway, the main thing there
to notice, we did the fly away,
but we also had the
animator still working
on the other things, and
that's important to know,
that the two things
can interact like that.
If you move things out of the
way, the animator is going
to go back to life and start
pulling down on things, okay?
So next time, we'll continue to
do the animation, we'll make it
so it's not so rickety, okay,
so we don't have this problem
where the bottom
load doesn't line up,
and we'll also do an
attachment, where we attach
to something and, you know, have
it swing from an attachment,
with a little attachment
behavior.
Alright, we'll see
you next time.
>> Announcer: For more, please
visit us at stanford.edu.
