[MUSIC]                         
Stanford University.            
>> Okay, well,                  
welcome to Lecture number       
12 of Stanford CS193P,          
Fall of 2017. And today,        
we're gonna continue the demo   
we started with Emoji Art and   
we're gonna,                    
we learned a little bit about   
table view in the last one.     
This time, we're gonna learn    
more about collection view and  
also learn a little bit         
how drag and drop, and          
collection view and table view  
all go together. And then I'm   
gonna go back to the slides     
and talk about TextField.       
And I originally had planned    
to do a demo in Emoji Art,      
of adding a TextField           
in there, but                   
we also have to finish early    
today, because there's some     
huge midterm, in this           
room right after us, and        
we have to have time            
to clear out of here.           
So, I will probably do that     
demo first thing, next Monday,  
or I might just skip that       
demo, we'll see how it goes.    
All right, so                   
back to Emoji Art here.         
What we're gonna do is make     
first I'm gonna make Emoji Art  
scrollable, because we didn't,  
it just currently,              
it's fixed. Then we're gonna    
add a collectionView along      
the top there,                  
you remember it from the demo,  
where we're gonna be able to    
choose our emoji from. And      
then we're gonna add some       
drag and drop from that         
collectionView, both into our   
view and into other apps, and   
vice versa, etc.                
So let's, actually,             
let's take a quick look at      
what our app looks like so      
far, okay, and it's             
basically working nicely and    
that we can pick up images.     
So I pick up an image here and  
drag it in and                  
drop it to change it.           
And of course, we have our      
table view on the left for      
choosing documents and          
adding documents.               
Of course, we haven't hooked    
our table view up, and          
that's okay, but because we're  
gonna do that next week. But    
one thing I wanna have you      
note about this table view      
that's kind of annoying is      
that I can't get rid of it.     
See this table view right       
here? You can't swipe it away,  
and that's because              
essentially, this app thinks    
it's in landscape mode on       
an iPad, and so of course,      
this master and the detail to   
splitView are side by side.     
But, since I'm in               
multi-tasking mode right here,  
so much of my                   
screen is taken up,             
with Safari over                
here on the right,              
that it's annoying because I    
really wanna focusing on my     
Emoji Art document. So I'm      
gonna talk to you a little bit  
how to make it so that that     
splitView on the left can be    
slid out of the way, even in    
splitView and landscape mode.   
So that's the first little      
thing we're gonna do. So let's  
hop on over to our code over    
here and see how we do that.    
It's quite easy, actually,      
splitView has a var,            
a property in it called         
preferred display mode, and     
you can control what happens    
with the master through that.   
And, it's just that the         
default here is not what we     
want. Now the kinda             
kooky thing about that,         
I'm gonna set this var in my    
master code. So I'm gonna go    
to my emojiArtDocument          
TableViewController, right?     
That's the TableViewController  
with the one, two, three,       
the thing that we want          
to slide out. And               
what I'm gonna set it is        
kind of an unusual place.       
I'm gonna set it in             
viewWillLayoutSubviews. And     
you might be like, whoa,        
viewWillLayoutSubviews,         
that seems like a weird         
place to set that. Well,        
the reason I'm gonna set it     
there is cuz when the layout    
changes, of a splitView,        
it often resets that preferred  
mode. So if I wanna keep        
enforcing this thing of it,     
the master being in slide       
on top mode, I have to keep     
telling it to do that, but      
I also have to be careful       
because setting that preferred  
mode can cause it to relay      
out. So I don't wanna end up    
in an infinite loop here,       
right, where in                 
LayoutSubViews,                 
I'm setting preferred mode,     
it's causing a layout,          
I'm coming back in. So I'm      
gonna do this by saying, if my  
splitViewController?.prefer-    
red,                            
to call preferredDisplayMode    
!= the one I                    
want. And you can see           
there's quite a few here,       
there's primaryOverlay,         
there's primaryHidden,          
there's Automatic,              
there's alwaysShowBoth, etc.    
But the one I want is           
primaryOverlay, so if it's not  
primaryOverlay, then I'm gonna  
set my splitViewControllers,    
preferredDisplayMode =          
.primaryOverlay. And so         
that'll keep enforcing          
it every time, even if,         
every time we rotate or         
whatever,                       
I'm gonna keep forcing this     
cuz I always want that, this    
table view to be appearing      
on top of my emoji art view.    
But I also wanna be able        
to swipe it out of the way,     
I just swiped it                
out of the way.                 
Wait, you can't see, hold on,   
I'll show you. Let me hide      
here, Hide Others, okay, so     
here, I'm swiping it in, and    
then I'm swiping it away.       
Swiping it in, swiping it       
away, and I always want it to   
be that way because it's very   
unimportant to access this      
table. I just go in here,       
pick the document I want, now   
that the document's in there,   
I wanna be having as            
much room to you know,          
to drag my stuff in and         
work here as possible.          
Do you understand that          
primary overlay thing?          
And I'm gonna ask you to do     
that in your homework, just so  
you kinda see, what it's        
all about there. All right,     
the next thing I wanna          
do is to make it so             
that my EmojiArtView            
is scrollable and               
zoomable, right, cuz right      
now, it's just a fixed image.   
And we already know             
how to do that, so              
I'm not gonna waste too much    
time showing you how to make    
it scrollable, I'm gonna do it  
quickly. I'm gonna have some    
precanned code to do it, but    
it's nothing new, it's nothing  
that you haven't seen before,   
in our previous demos.          
So I'm gonna go back to my      
storyboard, here it is,         
right here. I'm gonna go down   
to this viewController right    
here, and instead of,           
right now, what we have,        
just to remind you,             
is we have this drop zone.      
And inside the drop zone,       
we just put our EmojiArtView.   
That's why it's not scrollable  
right there. So I'm gonna       
delete it, and instead I'm      
gonna put a scrollView there,   
so I'm gonna go down here and   
search for a scrollView,        
here it is. I'm gonna drag the  
scrollView in here, I'm gonna   
pin the the scrollView to       
the edges of the drop zone,     
of course. So I'll go here and  
just pin it right up to the     
edges. We know how to do that   
with this little pin thing,     
bloop, it spins out, that's     
great. Now I'm going to create  
an outlet to this scrollView,   
put it up, where are we gonna   
put it? Let's put it right      
under the drop zone, in here.   
So I'll Ctrl+drag,              
create that scrollView.         
Now we know that when we        
have a scrollView outlet like   
this, by the way, down here,    
this emojiArtView is no longer  
gonna be an outlet. Okay,       
it's just gonna be              
a regular var and               
I'll just set it = creating     
one. This is exactly what we    
did with our image view in our  
other demo. So we haven't done  
anything new here. And when we  
have a scrollView like this,    
we remember we've got to set    
its minimum scroll view,        
maximum.                        
We've gotta set the delegate,   
we've gotta implement           
that view for zoom.             
Remember all that? So I'm       
gonna do all that really quick  
here. Trying to remember what   
I called, yeah, emojiscroll.    
So here it is, here's all that  
code. I just pop it in there.   
In fact, let me go over         
here and show it in big, so     
you can see it. So              
here's the ScrollView Outlet.   
So I just added a didSet        
to it, to set those things,     
right, the delegate. And        
then I added it as a subview.   
Here's viewForZooming.          
We're obviously zooming         
in our emojiArtView.            
Then I added a var here,        
emojiArt background image,      
which does the stuff we need    
to do like setting our content  
size equal to the frame.        
Right, remember we want that.   
We always want that frame of    
our image view to the same      
as our content size.            
I put a little bit of zooming   
code in here you can go         
look at later,                  
which is kind of fun,           
to give it an initial zoom      
that's good. And then,          
of course, we need to go        
down here and use this.         
So instead of just setting the  
emoji art, we use background    
image directly, I'm gonna use   
this emoji art background       
image var that I just created.  
That's this var right here.     
Hey everybody. See everything   
I did right there?              
And of course it's complaining  
that I'm not a UI split view    
or UI scroll view delegate      
by the way, so I'll do that.    
UI scroll view delegate,        
now I implement that. So        
let's make sure this all        
works. So here I am in my app,  
I'm just gonna swipe that       
thing out of the way.           
I'm gonna grab an image         
here and drag and               
drop it in. Here it is and      
hopefully I can scroll. Whew!   
I can I can scroll way          
in scroll pan around            
scroll in but you know what?    
That looks incredibly ugly      
to have that thing in           
the upper left. Like that,      
if I really were working        
on this thing, and I have       
to all my work in               
the upper left,                 
that would be absolutely        
ridiculous. So                  
what I really want is, I want   
this thing to stay centered.    
As I'm zooming in and out,      
when I'm zoomed out here.       
And when I zoom in, I want to   
say in the center. Not jump up  
there to the left like that.    
So how am I going to do that?   
Well, there's a lot of ways to  
do that, actually. I'm gonna    
do it in a simple way that      
lets me teach your about how    
to control the constraints in   
your storyboard from code.      
That's what this little thing   
is all about that I'm gonna     
show you here. So what I'm      
gonna do is I'm gonna go back   
to my storyboard.               
And I'm going to                
have this scroll view right     
here always be centered.        
So I'm going to keep this       
scroll view in the center,      
now, normally that's already    
happening, because I'm pinned   
to the edges. So of course      
it's in the center, but         
what I'm gonna do then is have  
the scroll view's width and     
height stick to its content     
size. So if you zoom in so      
that the content area           
gets really small,              
the scroll view is gonna get    
small and it's gonna stay       
centered. So that's how         
we're gonna do this, that's     
the trick. So how we gonna do   
that? Well, of course we need   
to make it to our scroll view   
right here stays centered.      
So I'm gonna click down here    
and just pick horizontally and  
vertically in the containers,   
so now it's centered.           
Again, that's not doing         
anything because those other    
constraints. But I still want   
these other constraints over    
here. I just don't              
want them to be fixed.          
I want them to be greater than  
or equal. This is something     
we did in the previous one, as  
well. So I'm gonna edit all of  
these ones about the edges to   
just be greater than equals,    
because I really just want      
my scroll view to never go      
outside the bounds.             
But I'm fine if my scroll view  
gets smaller than the bounds,   
I just don't want it to get     
bigger than the bounds, so      
that's why I'm putting this     
greater than or equals into     
here. Now you can see that      
things have turned red. That's  
because it's undetermined       
right now what size the scroll  
view is. Because we             
turned those equals to be       
greater than or equal, so it    
doesn't know how big it is. So  
I'm going to fix                
the size to start.              
I'm gonna ctrl drag to itself.  
And                             
fix both it's width and         
height. That fixes it, but      
of course now the scroll view   
is always gonna be this size    
which is, we'll look over here  
and find out. 748 by 703 and    
a half. So I clearly don't      
want that. What I want to be    
able to do is make this         
is make this width and          
height equal to the scroll      
views content size. Now,        
unfortunately I                 
can't do that here.             
I just know the way to          
control drag. To do that,       
I have to do that in code. So,  
I'm going to make outlets to    
these two constraints and then  
modify those outlets in code.   
So, that that within height     
is controlled by my code.       
So, that is the trickery here.  
And                             
the last thing I wanna do       
though is I'm gonna try and     
set the scroll view size to     
its content size. But if it     
gets really big, I want these   
other constraints to win.       
I want the constraints that     
keep it from going out, so      
the edge is to win.             
So that's why I'm going to      
set the priority of these two   
height ones, the height and     
width ones, to be lower. So     
here's the priority over here.  
It's currently at               
the required level.             
I'm gonna move it down to low   
priority for both of them. And  
so that will be fine when it's  
inside the bounds because it    
won't be conflicting. But once  
the scroll view gets big cuz I  
zoomed way in then it will get  
pinned to the edges which is    
perfect. All right so how       
do I make outlets to these?     
Just control drag of course.    
So                              
I'm going to bring up my code   
and we'll put it right there.   
So I'm gonna ctrl               
drag from with.                 
Over here you can see that      
the type of this outlet is NS   
layout constraint. I'll call    
this my scroll view width.      
Same thing here with            
the height. We'll ctrl drag.    
This one's going to be my       
scroll view height. Now         
what are we going to change     
about these constraints?        
So if you look at the           
constraints in the inspector,   
let's inspect                   
these constraints,              
like constraint width. These    
are all the things you can      
set in a constraint,            
right, the items involved,      
the relationship whether it's   
equal to, greater than or       
less than. And                  
look you can set the constant   
which is currently 703 and a    
half. This is the thing I want  
to change to fix my width,      
this constant right here. So    
I'm just going to change        
that constant in my code.       
Now when do I need to change    
it? Get so you can see here.    
When do I need to               
change these constants?         
Well anytime I zoom I           
definitely need to change it,   
right? Because as I'm zooming,  
I want my scroll view to        
be changing size. So,           
let that's in scroll view did   
zoom delegate method. And       
all I'm going to do in here     
is set my scroll view height    
constant equal to the scroll    
view's content size.            
ContentSize.height.             
And same thing here, the        
scrollViewWidth.constant is     
equal to the                    
scrollView.contentSize.Width.   
So now I'm just fixing          
the width of the scrollView to  
its content size. Now again,    
if it gets too big, this,       
this constraint is gonna lose,  
cuz it's low priority.          
The other place I need          
to do it is, obviously,         
when I first set up             
the image down here,            
when I'm first setting all      
these content size and          
all that. So right here         
I'm gonna be careful and        
optionally chain in case this   
gets called during a prepare.   
Might, get, do that and then    
the, I have the content size,   
actually, in a local            
variable here, size,            
from setting these things up    
here. Okay. And that's it.      
So let's go see if this is      
enough to make this work. And   
controlling your constraints    
from code, I'm gonna show you   
another example. I'm not gonna  
actually do the other example,  
cuz I don't wanna,              
I don't have time in the demo   
to show you things twice. But,  
we'll see another place where   
it would make sense             
in this very app. So            
here I'm going to drag in,      
it's sizing it to this size,    
now watch, I'm going to         
zoom in, the scroll view        
is staying the size of it's     
content size. I'm sorry,        
you guys can't see, recall,     
always remind me of that,       
because it's hard for me to     
remember that. So what I did,   
I dragged this in,              
started here, and               
now I just shrink it down and   
you can see that the scroll     
views' bounds are staying       
hooked to its contents.         
And even if I make it very      
large, now the scroll view's    
bounds are way bigger           
than the borders but            
those other constraints         
are higher priority.            
So the scroll view is           
actually, you can see it        
the scroll view indicator's     
there on the right edge,        
it's actually staying           
inside the bounds. Okay. So     
pretty simple, cool fix for     
keeping this thing centered     
right here. All right so        
that's that little trick to     
get back to our code and start  
talking about our collection    
view, here it is. So we're      
gonna add that collection view  
along the top that just has     
a bunch of emoji that we're     
going to use to drag in to our  
little UI. And how are we       
gonna do that? Well, it's       
pretty easy actually. Let's     
start in the storyboard. And    
here's our, this is where       
we're gonna be adding it.       
Right here,                     
same place we just were. Now,   
one thing about when you're     
manipulating your views,        
there's a really strong         
tendency to dive right in here  
to these things and just        
start grabbing the handles.     
Grab this, like I wanna put     
this collectionView on top, so  
I really just wanna             
grab this handle and            
pull it down to make room. But  
you cannot do that. Because     
you have constraints that are   
holding that thing to the top.  
And if you just start           
dragging it down,               
all your constraints            
are gonna turn red and          
yellow Things like              
this can be terrible.           
So if you really want to pull   
that down, you've gotta unhook  
it first. And really, this      
requires you go a little bit    
slower on your kind of editing  
to think ahead, am I going to   
have to unhook something? So    
we definitely have to unhook    
this top connection             
here of the drop zone           
to the top of the view,         
because we're gonna put         
a a collection view in          
between there, all right?       
So where is that connection     
to the top? I've got the drop   
zones collect, selected         
here in the outline, and        
here we got right here. Align   
top to the safe area, I'm just  
going to delete that. Now it's  
no longer hooked to the top.    
Now I can safely drag it down   
to make room for my collection  
view. And eventually I'm gonna  
put my collection view in and   
put a constraint that hooks     
the collection view in.         
All right, so how do we get     
a collection view? We just go   
down here and search for        
collection view, this is the,   
you know, pre-packaged MVC but  
I already got my MVC so         
I just want this one which      
is the collection view.         
We're gonna drop it in here.    
Let's go ahead and              
do its constraints. So I want   
it hooked right up to the top,  
I want it right to the left,    
right to the right.             
I actually want some standard   
spacing here to the bottom      
which I'm hoping it's going to  
say it's nearest neighbor is    
that drop zone.                 
So let's try that.              
Looks like it worked, but       
what happened to my collection  
view? It disappeared. Why did   
my collection disappear?        
Let's look at its constraints.  
Here's its constraints. It's    
got the trailing, leading,      
bottom space to the drop zone,  
top to the safe area. What's    
the height of the collection    
view? Not specified, right?     
It's like zero.                 
We never set the height.        
Now, what do we want            
the height to be?               
Actually we want the height     
to kind of be big enough to     
include those emoji and want    
those emoji to be whatever      
size the user's accessibility   
font is, right?                 
That's what we really want.     
I don't have time to show you   
that but you know what you      
need to know to make that work  
because what we would do is     
create the height constraint    
in here. And then wire          
it up into our code and         
then we would set it based on   
the size that is necessary to   
fit the font,                   
the accessibility font.         
But in this case what we're     
going to do is we're just       
going to fix its height.        
So I'm gonna go here.           
I've got the collection view    
selected. Oops wrong one.       
I'm gonna go here and           
fix its height.                 
I'm gonna fix its height to     
be about 80 points high or      
so. 80 points is enough to      
make an emoji that kinda fits   
under your finger nicely and    
it's a good default size.       
So there's my collection        
view reappearing. Another       
thing we wanna do is set the    
size of these cells. Cuz we're  
gonna have a bunch of cells     
in our collection view,         
that's what a collection view   
is a bunch of cells in there.   
Remember from the food demos,   
all the food things?            
So you do that by               
inspecting the collection       
view under the size inspector   
over here. And you can see our  
cell size is 50 by 50, I'm      
gonna make it a little bigger.  
Let's go whoops, 80 by 80.      
And there's one other thing we  
wanna do about this collection  
view, is that we want it        
be scrollable horizontally.     
We want all those emojis to     
be falling off to the right,    
or to the side of the screen.   
We don't want them              
going down, so I'm gonna go     
back to the normal inspector    
collection view and make sure   
that my scroll direction is     
horizontal. So that it's        
scrolling horizontally.         
In collection view,             
you can only scroll in          
one of two directions,          
either vertically or            
horizontally.                   
It doesn't do them both. The    
other thing about collection    
view, very important to         
understand, never make your     
cell size bigger than           
the non-scrollable width or     
height of the collection view.  
Collection view does not        
know how to have cells that     
are bigger than will fit in     
the direction it doesn't        
scroll. So you have to ensure,  
like in your homework           
you're gonna be making your     
cells different sizes, make     
sure you make it bigger than    
the width of                    
the collection view.            
It doesn't really know how to   
deal with that. So this is      
nice now. These cells are just  
gonna have an emoji in them,    
remember? So let's go ahead     
and put a UI label in there so  
we can put our emoji in there.  
We'll just put this in here.    
Let's go ahead and just do,     
how about vertically and        
horizontally centered? Let's    
make the font a lot bigger,     
although I'm gonna              
set the font in code,           
again because I want it to be   
accessibility friendly there,   
but just so that it looks       
nice in my storyboard,          
I'll set it to 64 points,       
nice and big. And then I'm      
also going to put just a nice   
little smiley face or           
something in there.             
So, again, this is mostly,      
I'm doing this just so          
it looks nice in                
the storyboard, right here.     
So, I can kind of imagine       
what my thing is gonna,         
look like right here. Now,      
let's go to our code and start  
loading up this collection      
view with some emoji.           
All right, let's go over here.  
Let's bring up our code,        
we have to create an outlet to  
it of course. So let's go down  
there, right before all         
our drop business and           
we'll put our collection        
view stuff here.                
So I'm just gonna Control drag  
from the collection view into   
my code, make sure that it's    
in the collection view, it is.  
I'm gonna call it, I'll call    
it emojiCollectionView.         
So there's my                   
emojiCollectionView.            
Now whenever you wire up        
a collection view like this,    
where you've dropped            
it in to a MVC,                 
the very first thing you're     
gonna wanna do. All the time,   
is go and do didSet. And        
set you new collection view's   
data source,                    
To be yourself and              
the emoji collection view's     
delegate to be yourself.        
Now if you do that prepackaged  
collection view thing where     
you get the whole MVC it        
will do this for you.           
But if you drag your            
own collection view in          
your definitely wanna do this,  
and of course it's complaining  
that I don't implement those    
protocols so we'll go up to     
the top and say.                
UICollectionViewDataSource,     
and UICollectionViewDelegate.   
And                             
by the way, while you're here   
you probably also want to do    
UICollectionViewDelegateFlowL-  
ayout.                          
This one you automatically      
get to be if you're             
the CollectionViewDelegate.     
This is the delegate            
of the thing that does all      
that text-like flowing layout.  
Remember the collection's       
layout is completely            
configurable? But this is the   
default one so I usually throw  
this in here, too. It just      
helps with escape completion,   
and all those kinda things.     
Now it's complaining because    
I don't implement one of these  
protocols. Let's find out       
which one. It's the one         
UICollectionViewDataSource.     
I don't implement that.         
It has required methods in its  
protocol, even though it's      
an Objective-C protocol.        
Let's see what they are.        
I'm gonna hit Fix and           
it added them for me right      
at the top of my file.          
I'm gonna move them, but the    
two are numberOfItemsInSection  
and cellForItemAt.              
Of course, those are two of     
the three we talked about.      
The other was                   
number of sections.             
We don't have to implement      
that because it defaults to     
one. That's true for            
tableView, true for             
collectionView as well. So      
I'm gonna move these back down  
here where the rest of my       
collectionView stuff is, and    
we're gonna implement those.    
So we need a model for          
this part of our MVC. And       
I have this as my model, which  
is an array of emojis strings   
so I actually took a string     
of emojis and I mapped it       
to an array of strings.         
Hopefully everybody's           
getting comfortable with map.   
Map just takes a collection     
and turns it into an array      
where it executes this closure  
on each of the items. So        
now emojis if you look at its   
type is array of string, and    
each string is one emoji.       
Okay, so how many items do I    
have in my only section? Well,  
of course, it's the number of   
emojis. That's how many items   
there are in the collection     
view. I only have one section,  
and that brings us down here    
to the all-important sell for   
item at where we                
have to let some                
cell =                          
collectionView.dequeueReusabl-  
eCell with ReuseIdentifier,     
right? And we're gonna have to  
specify something. I'll call    
it an EmojiCell, and for        
index path. There that's        
the index path we're creating   
the cell for. And we're         
gonna use the return cell.      
Now we need to load up          
this emoji into that cell.      
And for collection view, all    
the cells are custom cells.     
You have to have a subclass     
of, if you're gonna have any    
outlets to anything,            
you have to have a subclass.    
Because we couldn't have        
an outlook in our collection    
view itself that                
pointed to the emoji            
because there could be          
a hundred cells. And so         
we just can't do it, and so     
instead, we have to go and      
create a new file, which is a   
subclass of UI collection view  
cell. This one is actually      
on the right one.               
I'm gonna call this an emoji    
collection view cell, right?    
Subclass of UI collection view  
cell. So it was created here,   
let's put it in the right       
place. Okay, here it is,        
right here. I'm gonna mutely    
go to my story board,           
where's my story board?         
Here it is, and I'm going       
to inspect this cell. And       
I'm gonna set its reuse         
identifier to emoji cell,       
that was the thing I dequeue,   
whatever,                       
do reusable cell with, and      
I'm gonna set its identity to   
be an emoji collectivity cell.  
All right? So this cell is      
of type my subclass, and        
its identifier of this cell,    
didn't I type that in there?    
Emoji cell? Emoji cell,         
that's its type.                
All right, so now that we have  
this, let's go ahead and wire   
up this little label where      
we're gonna put the emoji to    
that custom cell. Now, a lot    
of times, Interface Builder     
will not get this right,        
but it did this time.           
Where if you go to              
automatic mode,                 
it kinda realizes that that     
thing that you have selected,   
could be hooked up              
to the controller,              
if there were just one of them  
or more likely, it's hooked up  
to this custom cell. So you     
don't have to use automatic,    
you could use manual and        
go find the file. But           
automatic sometimes will work,  
sometimes not. So here we go.   
We've got this label. I'm just  
going to create an outlet to    
it in my custom subclass,       
so here we go. And              
then there into UI label,       
I'll call it Label.             
It's this cell's label and      
that's it. Now,                 
I'm not putting any other code  
in here, but I could. It would  
no be not unreasonable to put   
a bunch of logic in your cell.  
If you have logic that is per   
cell. Then putting it here      
could make a lot of sense.      
Just because this one           
only has an outlet,             
it's a very, very simple cell,  
doesn't mean you couldn't put   
other code in there. I don't    
want you to get the idea these  
are only outlet bags, they      
actually could have logic in    
them if it made sense as well.  
Probably will make sense in     
your homework test logic in     
your cells. All right?          
So we've got this cell. So      
let's go back now to our        
place where we're creating      
this cell. And we've got this   
dequeued reusable cell. For     
us to access the outlets        
of it, we have to cast it.      
We have to say, if let          
emojiCell equal the cell,       
as our custom subclass,         
EmojiCollectionViewCell.        
And if we can successfully      
cast it, then we can tell       
the emojiCell label, okay, to   
set its attributed text equal   
to something, text, so          
what is that something?         
Well, that something is gonna   
be taking one of these,         
whatever thing is at            
this index path, and            
set its font cuz I wanna        
control its font in code and    
then put it in there. So        
I'm just gonna let text equals  
NSAttributedString. The string  
of it is going to be            
the emojis sub indexPath dot    
item, that tells us which       
emoji we're talking about       
here. And the attributes,       
I'm going to just set           
the attributes of the font,     
that's the only attribute I'm   
gonna set. I'm gonna set it to  
this var font, which I'm        
gonna create up here,           
private var font, which         
is gonna be a UIFont. And       
I'm going to do the whole       
accessibility thing here.       
Which is, I have to use         
UIFontMetrics, all right? And   
I want the font metrics for     
the text style, dot body. And   
I'm going to scale the font.    
Scale font for,                 
and the font I'm                
gonna use is UI font,           
preferred font body, but        
I'm going to scale it up.       
I'll say it with size,          
it's a little easier,           
with size 64. So I want 64      
point, but I'm gonna have it    
scaled by whatever the          
accessibility thing is, right?  
So if your accessibility is     
in the middle, size of font,    
I'm gonna do 64 to              
make it bigger,                 
it'll be bigger in 64 and       
smaller.                        
Now, this is not going to work  
well right now because I don't  
change the collection view's    
size. So if I set this big,     
it's gonna be cut off, and      
if I set it really small,       
the collection view won't       
shrink up to kinda hold it,     
do you see what I'm saying? Do  
you see what I mean by that?    
So we'd have to add             
that later, but again,          
I don't wanna show              
you hooking up                  
to a layout constraint twice.   
So that's it. This is           
all we need to do to get our    
collection view loaded up.      
We implemented those            
data source methods             
that are required, right?       
Number of sections,             
number of rows, items in        
section and then the cell, for  
a certain one. And so let's go  
over here, so you can see. And  
sure enough, along the top,     
we can see right there that we  
have our emojis. It's really    
nice scrolls. The collection    
view is a scroll view, so       
it's scrolling back and forth,  
it's very nice. Now,            
the next thing we wanna do      
is be able to pick these        
things up and drop them in our  
nice background, like if        
this is our background here,    
we wanna pick these things up.  
Remember, I dropped the bees    
in there, the apple, or         
whatever. We wanna do that. So  
how are we gonna do drag and    
drop? Well, we haven't done     
drag yet, we only did drop,     
the only thing we've done       
is dropping in there.           
So I'm gonna show you drag in   
collection view's world, which  
looks almost exactly as same    
as non collection view world.   
The only difference             
between drag in collection      
view world is,                  
collection view helps you out   
with which index path are you   
dragging. It knows where your   
finger is, and it's like,       
you're dragging that index      
path and you're dropping it at  
that index path, so really      
just providing index path but   
otherwise, it's pretty much     
exactly the same. All right,    
any time you wanna do dragging  
in a collection view,           
the first thing you're always   
gonna do, just like you         
do a drop interaction is        
the first time you do drag and  
drop with a view,               
with a collection view,         
you're gonna set your           
collection view's drag          
delegate to be your self.       
And then, of course, that's,    
you're gonna go up here and     
you're gonna say, yes,          
I implement the UI collection   
view drag delegate. And         
as soon as you do that, it's    
gonna complain, no, you don't,  
and you're gonna click on       
this and it's gonna say,        
do you want me to add           
the protocol stuff?             
And you're gonna say, yeah,     
sure, what do I need to do?     
And it's gonna say, you         
have to implement items for     
beginning. If you remember      
from the lecture, items for     
beginning is the thing that     
tells the drag system,          
here's what we're dragging.     
So we have to provide these     
drag items to drag. So let's    
do that, let's move this down   
again. And in here,             
so what're,                     
how are we gonna provide our    
items for beginning? Now,       
notice the collection view      
one has add index path, so      
it tells us which thing, which  
IndexPath we are dragging       
from, which is really,          
really convenient for us. So    
I'm gonna create, I'm gonna     
call a little function here.    
I'm just gonna return           
dragItems at indexPath.         
This is a function I'm          
gonna have to write,            
private func dragItems          
at indexPath,                   
which is an indexPath, which    
is just the section, an item.   
And it returns this             
array of UIDragItem,            
those are the items that        
we have to return. So           
this all we have to do to get   
started with drag. And for us,  
again, it's really, really      
easy to implement this because  
what we're going to drag        
Is NSAttributedString,          
that's what we're gonna drag,   
that's an item provider         
just like NSURL,                
UIImage, NSAttributedString.    
Also, NSString we               
could, do but we're gonna do    
NSAttributedString, gives us    
a little more flexibility for   
what we're dragging around. So  
that's going to be              
our item provider.              
So all we have to do is get     
the attributedString we want    
to drag and then return         
it in the drag item and         
that's it. So how do we         
get that attributedString?      
So I'm gonna say, if I can      
let the attributedString =,     
and what I'm gonna have to do   
is look at this indexPath,      
find my custom cell,            
look at its outlet, get its     
attributedText. Everybody cool  
with that? That's how I'm       
gonna do this. So let's do      
this all in one line of code,   
right? So I'm going to first    
ask my CollectionView for       
the cell for                    
this item at indexPath.         
Now this is like                
TableView's cell for            
row at indexPath.               
Thing, this only works for      
visible cells but, of course,   
that's going to work here.      
I'm dragging this thing, it's   
got to be visible, right? So    
I've got this cell that we're   
dragging from right here.       
Now I'm going to as it to       
be my custom subclass.          
And if that works, hopefully    
it will, I'm gonna get its      
outlet, and I'm gonna           
grab its attributedText.        
So if all that works, I just    
grabbed the emoji at that       
indexPath. So                   
now that I have the emoji,      
all I need to do is create      
one of these UI drag items,     
using that attributedString     
as the provider, right?         
The thing that                  
provides the data. So           
I can do that by saying         
let dragItem = UIDragItem.      
And the drag item creator,      
you can see it right there,     
takes an ItemProvider. And we   
can create an ItemProvider for  
an attributedString by          
saying ItemProvider.            
And it has a few constructors   
but a really nice one is this   
one object where you just       
give it an object and           
it knows how to be              
provider like a UIImage or      
NSAttributedString.             
So that's what I'm gonna do.    
And I'm gonna give it this      
attributedString that I found   
in my cell. And that's it.      
This creates the drag item,     
and now we just return this.    
We return an array of them,     
but we're only dragging         
this one thing. But             
before I return it,             
I'm gonna do one other thing,   
I'm gonna set the drag          
item's local object             
to be that attributedString.    
Now what does this mean? Well,  
if your drag is local within    
your app, you don't have to go  
through all that itemProvider   
stuff, right? The asynchronous  
getting the data from that,     
remember all the stuff we       
had to do in the drop? You      
don't have to do any of that,   
you just grab                   
the local object.               
So this is a way of like        
short-circuiting all that,      
if it's a local drag. But it's  
gonna work to actually drag     
out of our CollectionView to    
other apps, but when we're      
dragging locally, we're going   
to be able to use this.         
So here I'm just gonna return   
an array of just this one       
drag item. By the way,          
if I couldn't                   
get the attributedString        
out of that cell for            
some reason. Then I'm just      
gonna return empty, so no,      
don't do any drag then. So      
it's gonna know from this       
not to begin a drag. Now,       
remember I also told you        
that once you start to drag,    
you can add more items by just  
tapping on them. So you could   
be dragging multiple things at  
once. That's easy to implement  
as well. Just like we have      
this items for beginning,       
we have another one called      
itemsforaddingto, which looks   
exactly the same as this.       
And we're gonna return exactly  
the same thing. Because it's    
giving us the indexPath         
that someone tapped on          
while I was dragging and        
I'm just going to get the       
emoji out of it and return it,  
and this is all that's          
required to do the dragging.    
Watch this.                     
I can drag just from that.      
Watch, here's the bee           
hold down and drag. And         
the thing about this is if I'm  
dragging, I can't drop in my    
CollectionView because I        
haven't implemented drop.       
But I can drop other places.    
I'm going to go over here and   
just drop this bee in           
the Google search bar.          
And it searched for bee,        
believe it or not. So that's    
pretty cool. So I got dragged   
up working to other apps,       
so I hardly had to do           
anything in my app,             
just provide that               
attributedString and drag and   
drop. So that's one of          
the cool thing about drag and   
drop, it's so easy to get it    
going in both directions. So    
now, we want to drop.           
Now we want to be able to pick  
this bee up right here and      
drop it somewhere else in       
our CollectionView, so          
let's go do that. All right,    
so to do the drop part of this  
just like we did when we went   
to do the drag delegate here,   
we have to do                   
emojiCollectionView.dropDele-   
gate = self.                    
And up to the top, look at how  
many protocols we implement.    
Woo, we're cruising today.      
So let's do                     
UICollectionViewDropDelegate    
and when we do that,            
wait for it to compile. It's    
gonna complain, it says you     
don't implement that protocol.  
Sure, fix. And it says, this    
one you must implement which    
is performDrop. Makes sense,    
right, you have to do perform   
drop or you're not even in      
doing drop. So let's copy and   
paste that one down here.       
I'm actually gonna implement    
perform drop last.              
Because there's a couple other  
ones that I need to implement,  
if you remember from what we    
did before? CanHandle and       
session moved, the session      
updated. Gotta, we can          
implement those two so that we  
get the right little plus sign  
when we're dragging it around.  
And so that we don't try and    
accept drops that we            
don't understand. So            
let's do the canHandle. Here's  
canHandle's collectionView      
version. Calling it canHandle   
looks almost exactly the same   
and it will be implemented      
exactly the same,               
which is I'm just gonna say     
if the session.canLoadObjects   
ofClass NSAttributedString,     
then I'm in. Cuz that's what    
my CollectionView can accept.   
This, by the way, means we're   
going to be able to drag        
just random strings into        
our CollectionView. Not just    
emoji, and first I was like,    
I don't want that but then I    
was like that's kind of cool.   
What if I wanted to put         
a label on something down in    
my picture. So I decided        
that's good, so I'm going to    
keep doing that. Then we        
have the sessiondidupdate,      
that we have to do,             
sessiondidupdate.               
Is that what is called?         
DidUpdate, is this the one?     
Yes, dropSessionDidUpdate and   
what do we need to do in here?  
This is where we need to        
return that drop proposal,      
either copy move or cancel,     
that's all we have to do. And   
you can see that here it's a    
UICollectionViewDropProposal.   
And why is that different?      
Well, let take a look at it.    
Let to return                   
a UICollectionView,             
CollectionViewDropProposal.     
[BLANK AUDIO].                  
And look at the constructors.   
And there's another             
constructor, second one,        
look at that, intent            
UICollectionViewDropIntent.     
Well, the intent in             
a CollectionView says,          
are you dropping this           
into this cell or               
you want to add a cell?         
You see the difference?         
So that's what we               
have to specify.                
Now in our case, we always      
want to add a cell, so          
you'll see that our intent,     
let's, sorry,                   
let's go back and pick that,    
we want this constructor.       
So the drop operation we're     
gonna do it first is copy,      
I'm gonna change that           
in a second. But                
then the drop intent we want    
is insertAt destination as      
opposed as to insert into       
the destination cell. Now,      
let's talk about copy. If I'm   
moving the bee around inside    
my collectionView, I'm not      
copying it. And I don't want    
the user to think that the bee  
is going to now be copied and   
there will be two bees.         
So it's move.                   
So I have to know, somehow,     
that I am inside my own         
CollectionView. Okay, so how    
am I going to do that? Well,    
what I'm gonna do, what's       
this problem by the way?        
Just the indexPath. Yeah,       
so how I'm gonna do that?       
What I'm gonna do is when       
I start my drag up here in      
itemsForBeginning, I'm gonna    
set something in the session    
called the localContext, and    
this is in any type any.        
And I'm gonna set it to be my   
collectionView. So this is      
just something in the drag      
session that lets droppees,     
people who have dropped know,   
hey,                            
this is a local drag, and       
here's the context of it.       
Well,                           
since this drag is coming       
from the collectionView,        
I'm gonna use the               
collectionView as the context.  
All right, so now I can look    
at this local context down      
here to determine whether       
my drag variables should be     
a copy or a move.               
So I wanna say something like,  
let isSelf is myself or         
whatever, = the session,        
Session, it has a thing called  
a local drop DragSession.       
That's the session with         
discharged it, .localContext,   
oops, localContext. I really    
wanna say if that = my          
collectionView.                 
This is what I'd like to do,    
but I cannot do this because    
this, what type is it?          
Any, and you cannot do ==       
with any, because remember,     
the == is just using the        
equatable protocol, right? And  
any can't have any methods or   
vars, it has to be casted to    
something before you            
can do anything on it.          
So you certainly can            
have equitable for any,         
you can't have anything for     
any. So                         
what I'm gonna do is take       
this little thing and           
attempt to cast it as           
a UICollectionView. I mean if   
it's not a UICollectionView     
it's not to be equal anyway so  
I might as well try it.         
Now if that's nil, we can do    
equatable with nil because      
optional can do equatable,      
all right? So now I know        
whether it's myself or not.     
So if it's myself,              
then I'm just gonna do move,    
otherwise I'm gonna do copy.    
Now I'm not,                    
I haven't even implemented      
performed drop yet.             
But let's take a look at what   
the collectionView does just    
with this small amount          
of information from us.         
So here's my                    
collectionView right here,      
now watch I'm gonna drag,       
click the coffee here.          
Look at the collectionView,     
look what it's doing,           
it's making space for           
me to drop in the new spot.     
Do you see that? I can still    
drop drag over here but         
now I'm dragging over here.     
And it knows that, I might      
be dropping there. And in fact  
if I drop, it doesn't work      
because I haven't implemented   
perform drop. But you           
could see the collectionView    
is already knowing what I'm     
doing. So                       
collectionView really cool for  
doing drag and drop, it's so    
powerful. We hardly do any,     
we bring four lines of code,    
to get this far in the drop.    
So let's go back here and       
do perform drop.                
Well, our string of four lines  
that go is going to end,        
because perform drop is         
a little bit more complicated,  
not a lot. But when the         
perform drop happens, we have   
to update our model, which      
is our list of emojis and       
we have to update               
the collectionView,             
all right. Also there's two     
different kinds of drops here,  
there's the drop where it's     
coming from my collectionView.  
In which case, I have to        
drop in the menu place, and     
remove it from the old place    
because I'm moving. And then,   
there's a dropping it's         
coming from some other app.     
Which is allowed, watch this,   
let's go over here and          
select some text.               
>> [INAUDIBLE]                  
>> Sorry you're not on the      
screen? Yeah, thank you.        
I will show you this, hide      
others. Okay, so I can go over  
here, and select this bee, and  
drag and drop it over here.     
And look, it's saying plus,     
and it's making room for it,    
and, I didn't do perform drop.  
So I have those two cases       
to do perform drop.             
The local case and Mac case so  
let's go do both those cases.   
We'll do the local case first.  
Now when we drop,               
collectionView has              
gives us this coordinator.      
This coordinator,               
I'm gonna make this a little    
easier to read because it's so  
long the name here, you can     
see there's two arguments to    
this thing. One, it's just the  
collectionView is involved and  
the one is this coordinator.    
Now this coordinator is gonna   
give us all the information we  
need to know to do this drop.   
The first thing                 
it's gonna tell us,             
the most important thing is     
the destinationIndexPath.       
Okay, this is obviously         
the IndexPath where we're       
dropping. And                   
that = to the coordinator,      
destinationIndexPath.           
But that might be nil, because  
you might be dragging it in     
a part of the collectionView    
that's not in between any of    
the existing cell so            
this could be nil. So if that   
happens, I'm just gonna create  
an IndexPath with item 0 and    
section 0. Okay, I could pick   
some other IndexPath but        
that's what I'm using           
my default. Okay, so            
now we know where we are        
dropping this drop. And now,    
it's just a matter              
of going through all            
these items in                  
the coordinators items. These   
items are UICollectionViewDrop  
items and they have some very   
interesting pieces              
of information.                 
For example,                    
if I can let sourceIndexPath    
= this item's sourceIndexPath,  
then I know that this drag      
is coming from myself, and      
this is the sourceIndexPath     
of it. So I don't even need     
to look at the local context    
in this case to know this is    
coming from me, awesome.        
And I know now the source and   
the destination,                
this is trivial. All I need     
to do here is update my model   
to have the source going        
to the destination.             
And then update                 
the collectionView to removed   
the one from the source and     
add it to the other one.        
So, this is probably the        
easiest case, this local case   
so let's do it. First,          
lets get the attributed string  
that we need so I can say,      
if I can let the attributed,    
this is the attributed string   
that we're dragging around.     
And luckily, I stashed          
it in that local object,        
remember that? So I'm gonna     
get the drag item, Item and     
get it local object. Remember,  
I can stashed it in local       
object up here when I made the  
drag item. I don't have to do   
any of that provider stuff to   
get it but I am going to have   
to say as NSAttributed string   
because its in any. So I will   
get to the attributed string    
which I'm going to be able to   
cuz I know I set that. Then I   
can put the attributed string   
in the new place and move the   
other one from the old place.   
So here we go, I'm gonna say    
emojis, this is my model,       
remove at                       
the sourceIndexPath.item so     
remove where the thing          
came from. And emojis           
insert this attributedString    
that's being dragged around     
at the destinationIndex         
path.item. Voila, I've updated  
my model. Okay, I moved b       
from one place to the other.    
Okay, destinationIndexPath,     
Path.                           
This one probably also          
up here, curly brace.           
Okay, so now I have to update   
the collectionView itself,      
which is no,                    
that's not a curly brace.       
What'd I do up there?           
Item, yeah, thank you,          
item. All right, so             
now we've built the model.      
Now we're gonna update          
the collectionView.             
So that's collectionView.       
Now I could, one thing          
I don't wanna do here,          
very important to understand,   
don't reload data here.         
Do not reload data in the       
middle of a drag, because it    
resets the whole world, it's    
bad, don't do it. So instead,   
I gotta remove the rows and     
insert the rows separately. So  
I'm gonna delete the rows       
at the sourceIndexPath. And     
then I'm going to,              
Insert rows,                    
InsertItems, sorry,             
I keep saying rows,             
use the table view at           
the destinationIndexPath. Now,  
This looks like it's.           
Insert items. So this looks     
like this would work fine but   
actually this would probably    
crash your program.             
And the reason for that is      
when you do multiple. This is   
indexpath.string. When you      
do multiple changes to your     
collection view, each step      
would normally have to have     
your model completely in sync   
which it wouldn't be because    
until I do both of these,       
the table won't be in           
sync with the model. But        
there's a really cool           
way to get around that,         
which is collectionView and     
tableView have this method      
called performBatchUpdates.     
And performBatchUpdates just    
has a closure. Inside that      
closure, you can put any        
number of these delete items,   
insert items, move items,       
whatever you wanna do. And      
it will do them all             
as one operation so             
that it never gets out          
of sync with your model.        
See what's happening there?     
It also has a nice completion   
thing here which we             
don't need in this case.        
But when it's all done          
with all the updates,           
it'll call that                 
completion closer. So           
don't forget to do batch        
updates if you do multiple      
adjustments to your tableView   
or collectionView. And          
then the last thing we need     
to do is ask the coordinator    
to do the drop. The reason      
we need to do this is,          
we need to animate the drop     
happening, right there. So      
we're gonna do the drop. The    
dragItem is the item.dragItem.  
And the ItemAt is               
the destinationIndexPath. So    
that's gonna actually           
make the drop happen.           
So this is going to animate     
and move the bee over.          
This is going to, at the same   
time, be dropping the thing     
that's on your finger is going  
to disappear, and the plus      
sign will go away, and all      
that business. All right, so    
let's take a look at this.      
All right, here we go.          
Now we've only done the local   
case, but here it is, the bee,  
moving it around and drop.      
Woo-hoo, it worked, all right?  
This over here, drop. Now this  
one over here from outside      
is still not gonna work.        
Doesn't work because that's     
not the local case, right?      
So let's do the local case.     
All right, so that's the else   
of this right here. Yeah,       
it's the else of,               
not that one, the else of.      
This one, the else of           
this source index path.         
So we don't have a source       
index path, which means this    
thing comes from somewhere      
else, so how we do this?        
Now this turns out to be quite  
easy to do too amazingly,       
but there's a little            
problem here.                   
If you're dragging something    
from outside and you drop it,   
is that information             
immediately available? No,      
you have to asynchronously      
go fetch it from that thing.    
Well, what the heck are you     
gonna do with your table        
while you're off fetching it?   
What if it takes ten seconds?   
So                              
what you do is you put          
a placeholder in your table.    
And collection view manages     
all of that for you, so that    
all you have to do is when      
the data finally does arrive.   
You tell the placeholder,       
context it's called.            
Okay, I got the info.           
Update your model, and          
it'll automatically swap out    
the placeholder cell for        
one of your cells that matches  
the kind of data you have. So   
let's see how we do that.       
We do this by creating          
a placeholder context.          
This is a thing that's gonna    
manage that placeholder. And    
placeholderContext, you         
get from the coordinator,       
oops, coordinator,              
by asking it to drop the item   
to a placeholder. You see       
the second initializer there,   
dropped item to a placeholder.  
So I'm gonna do this one. So    
the item I'm gonna drag         
is the item.drag item.          
Remember, we're still in this   
for loop where we're dropping,  
cuz we could be dropping        
multiple items.                 
So we're dropping them one      
by one. So that's what we're    
dragging. And then here's       
the placeholder right here.     
So I gotta create               
one of these.                   
Let me make this a little more  
readable for you here. Okay,    
let me put this on another      
line. All right, so I've gotta  
create a UIDropPlaceholder.     
And to do that, I, it needs to  
know where you're gonna         
insert the placeholder. And     
then it has a reuseIdentifier,  
and I'm gonna talk about that   
in a second. So let's put       
the insertionPathIndex to be,   
obviously the destination.      
Okay. Where                     
we're putting this in. That's   
this thing we calculated right  
at the beginning up here.       
That's the destination. And     
look at this reuse identifier.  
What the heck is that?          
Well you get to decide          
what kind of cell               
is the placeholder. It doesn't  
put some prepackaged one in.    
You get to decide. So this      
is asking you for the reuse     
identifier in your storyboard   
to use to create that thing.    
So I'm gonna call mine          
DropPlaceholderCell.            
I can call it anything I want.  
This is just the string that    
I'm gonna use in my storyboard  
to create this thing. Now       
what's interesting also is you  
can also include at the end of  
this a closure. And in that     
closure you can basically,      
initialize this cell or do the  
same kinda thing you would do,  
where you do the                
dequeueReusableCell, because    
that dequeueReusableCell's      
never gonna be called. This is  
the placeholder cell, it's      
not gonna call that thing. So   
here you could do the same      
kinda setup if you had outlets  
in your cell, or whatever,      
you could set them all up.      
We're not gonna have            
any outlets in our, so          
we're not gonna do it, but      
that's where you would do it.   
So did I remember, so I just    
wanna make sure we got this     
all right, no errors. So let's  
go back to our storyboard and   
make that placeholder cell.     
The way you make a cell         
in a collection view,           
you just select                 
the collection view and         
go over to inspect it. And the  
very first thing is the items,  
and I want from one item        
to two items. Okay, and         
it makes a second item right    
here. And I'm gonna go make     
sure I say it's not an emoji    
cell, it's a drop placeholder   
cell. That's how I'm linking    
it to that line of code I       
just wrote. Its type doesn't    
have to be emoji collection     
view cell because it's not      
gonna have the emoji in there.  
So I'm gonna make it just be    
a normal UI collection view     
cell. Nothing special, and it   
doesn't need this little label  
on the inside because           
it's a place holder for         
the label, that information     
hasn't arrived yet. So          
instead I'm gonna put an        
activity indicator in there.    
So it's spinning there,         
letting the user know I'm       
waiting on some dropped data.   
So I'm gonna put it in there.   
Let's go ahead and center it.   
And let's yeah,                 
that's probably good enough.    
And let's make it so            
it starts off animating. So,    
I'm gonna click it right here.  
So it starts off animate,       
so I don't even have to tell    
it to animate. All right,       
all that. And                   
what are we using here? Emoji,  
I thought I changed that,       
I guess not. Yeah.              
Didn't I change that already?   
I did. Placeholder cell.        
So now that we have this setup  
for this placeholder cell,      
we go back here to our Code.    
No, not there. Down here.       
Okay, and we've got this nice   
placeholder ready to go.        
All we need to do now           
is go get the data.             
And when it arrives, we just    
tell the placeholder context,   
here's the,                     
go swap them out and            
here's my model change.         
So, I'm gonna get the data      
a little differently            
than we got before.             
Last time we used that          
method's load objects,          
plural, on session to load up   
the objects, remember that?     
When we dropped                 
the image in there.             
This time I am just gonna grab  
one thing, not load objects,    
but grab one object             
that was in my item.            
So I'm gonna say here           
item.dragItem.itemProvider.     
So this is the item provider,   
that thing that's provided      
me the item, provides it        
asynchronously because it's     
outside of my app.              
Load object,                    
I'm gonna say of class,         
I want an NSAttributedString.   
And it gives it back to         
me asynchronously with          
the provider. That's gonna be   
the attributed string, and      
also possibly and error, which  
we're gonna ignore the error.   
You can look at the             
documentation to see what kind  
of errors you can get.          
But you can imagine right,      
errors providing this data.     
Now                             
this particular closure is not  
executed on the main queue. So  
this one we need                
to unfortunately                
say DispatchQueue.main.async    
if we wanna do anything,        
to our UI which we do.          
What we're gonna do here,       
is we are going to change our   
model which are gonna cause     
some UI stuff to happen.        
Now, it could be actually that  
the change in this would not    
affect the UI directly cuz      
we're only changing our model.  
But the problem is we're gonna  
do it in the context of asking  
the placeholder to              
replace that cell, and          
that's certainly gonna cause    
UI. So how do we do this?       
We just say                     
placeholderContext.commitInse-  
rtion of my data. And           
this right here is              
the insertionIndexPath,         
and here is the code to fix     
my model, and that's it.        
This is all we need to do and   
it will automatically           
replace that placeholder with   
a cell by calling your normal   
self or item at methods.        
Notice that this                
insertionIndexPath might        
be different than this          
destinationIndexPath.           
Why? Because this might have    
taken ten seconds, not likely,  
but it might have. So it might  
have changed other things in    
the collection view might       
have been going on. Okay, and   
new cells adding, other things  
came faster whatever. So        
always use the insertion index  
here, and you're only using it  
to update your model. So        
how do I update my model here?  
Well that's my emojis.insert    
the thing that                  
came back which is this         
provider as an attribute        
of strings. So let's say if     
we can let attributedString     
= provider as                   
an NSAttributedString.          
Okay, then we can do this.      
So, insert that                 
attributedString at             
the insertionIndexPath.item.    
That updates our model,         
this thing handles the rest.    
You don't have to               
do anything else,               
you don't have to do            
any inserting rows,             
any of that business. Yeah,     
this is attribution.string,     
cuz we have just strings in     
our model, not attributive      
strings. And of course          
we need you to do self.,        
right here because we're        
inside a closure. Now if for    
some reason you couldn't get    
that attributedString from      
the provider,                   
maybe there's an error          
instead. Then you wanna let     
the placeholderContext know     
to delete that placeholder.     
Because you couldn't get        
the other string after all, so  
you go, and that's it. So       
all you have to do to accept    
stuff into a collectionView     
from somewhere else. So         
let's see this in action        
right here. So we               
haven't hopefully broken our    
local. Nope, still working,     
and hopefully where you can     
get our bee and drop it in,     
here we go. Woo-hoo,            
we got a bee, now our font is   
really big, so we can't see it  
we'd probably wanna have our    
font self-adjust or whatever.   
But this is, you know, just     
like anything from now we can   
move this around, it's part of  
our collectionView etc. So      
that's collectionView drag and  
drop start to finish not        
really that complicated it's    
actually they did a pretty      
good job. Now the next thing    
we wanna do is to drag these    
things into our image, right?   
We have our, oops let me go     
back to in my images here,      
and, where's my                 
favorite image?                 
And well, pick some             
random image here we go.        
All right, so                   
I have my image here, and       
we want to be able to pick      
up an apple and put it          
under the tree. So how are we   
gonna do that drag and drop?    
Well, we just, all we need to   
do is implement dropping of     
NSAttributedStrings in our      
EmojiArtView. That's all you    
need to do and it's so simple   
let's do that quickly here as   
time is running out. So, let's  
go to our emoji art view so     
here's our EmojiArtView,        
it kind of looks very           
simplistic at this point.       
And I'm going to add or         
drop interaction to it,         
init's initializers. So         
I have this nice thing I type   
which is the template for       
having UI view initializers.    
Remember you have to override   
both these inits,               
remember that? And              
then I have this nice setup,    
so in the setup right here,     
I'm just going to add           
interaction. And remember I'm   
in the UI view now, so          
I'm adding it to myself.        
UIDropInteraction with          
the delegate being myself,      
now I'm                         
a UIDropInteractionDelegate.    
I also have a nice              
little thing here,              
dropstubs that just             
gives me the stubs for          
the three methods canHandle,    
didUpdate, performDrop,         
you should be used to           
this now. Same as we            
had in the collection view but  
these are the non-collection    
versions. And                   
so what do I do in canHandle?   
I just say whether I            
can load the objects of         
the right class in this case    
attributedStrings. And what     
do I do in sessionDidUpdate?    
I have to return a drop         
proposal, here I'm always       
gonna allow dropping            
an attributedString. And it's   
always gonna be a copy because  
I'm not gonna move things       
inside myself with drag and     
drop. I'm gonna move them       
directly, so I'll always do     
copy here, and then finally I   
just have to load objects       
of a certain class.             
NSAttributed strings            
of course, and                  
this is the list of attributed  
strings, the item providers     
are attributed strings. And     
here I just need to add these   
things to my view as sub        
views add labels, sub view.     
So, I'm gonna do this with      
a little function here,         
add label,                      
then I'm gonna write.           
And it's going to get           
the attributed strings so       
let's get the attributedString  
that we need out of here.       
Actually I also need to         
know where to drop it so        
let's get the drop              
point by saying Mr.             
Session, drag session,          
what is the location of this    
drag in my coordinate system.   
So I'm just finding out         
where this thing is dropped     
I obviously need to know,       
where it's dropped to be able   
to do it. So, then let's add    
all the things that dropped by  
doing a little for loop for     
attributedString in             
the providers as?,              
an array of attributedString,   
which it should be. But maybe   
you didn't know you could       
do this, but you can say as     
an array right in the middle    
of a four loop like this. And   
in fact, you can even say if    
that for some reason is nil,    
cuz you can't as it,            
then just use an empty array,   
right here. Okay, that's kind   
of a cool trick. All right,     
so we're gonna add a label      
with the attributedString,      
we're doing this for each one.  
And we're going to have it be   
centered at the dropPoint,      
So we                           
have write this method ourself  
to do that private func, this   
is an easy one, addLabel(with   
attributedString:,              
of type NSAttributedString,     
centeredAt point: CGPoint).     
I'm just gonna create           
a UILabel. I'm                  
going to set its                
backgroundColor to clear, =     
clear, Cuz I want you know my   
image to show through around    
the edges of it I don't want    
a big white background or       
something. I"m gonna set the    
attributedText obviously to     
be this attributedString        
that was passed in.             
I'm going to size to fit it,    
okay I don't want that label    
to be some large random size.   
I'm going to what else am       
I gonna do? Yes I'm going       
to position it, label.center    
= drop point right there, and   
of course I have to addSubView  
to myself. That's it.           
Let's do it. All right,         
let's go get an image.          
Did I lose my favorite image?   
No, my favorite- there it is.   
This is my favorite image       
right here. Okay, so            
I've got my image right here,   
we can zoom in and out.         
We can pick up a bee, and drop  
the bee. Pick up another bee,   
drop the bee. Maybe we'll put   
an apple down here. Now of      
course we want to be able       
to resize these things, and     
move them around, right? So,    
I don't wanna waste your time.  
That's just Jack doing          
some gesture recognizers.       
I have put those in             
a little file right here.       
So let's just throw those in.   
And                             
you can go look at those        
later at your leisure,          
it's really, it's very simple.  
Gesture recognizers tap and     
pinch and pan, things like      
that. And all we need do is to  
turn that on, let's just go     
down here and say addEmoji      
GestureRecognizers to           
that label, so                  
that just adds these            
recognizers to the label.       
Okay, so                        
let's see that in action.       
Let's just get this out here,   
drag this in. Now,              
we drag a bee down here.        
Drag another bee, this is       
what I was doing at the very    
beginning to demonstrate this.  
And then we can tap on them     
and make those bigger,          
tap on them and                 
make them smaller.              
We can even zoom way in,        
before we make some really      
small, take like apple put it   
down here. Make it              
very very small, right?         
And then we zoom back out. It   
will be a tiny little apple,    
etc.. Now, I'm going            
to back to the slides.          
Like I say,                     
when I finish the slides,       
we're not gonna be able to do   
the text demo because we have   
this midterm coming in. But     
that's pretty much all we need  
to do to make this collection   
view, do full drag and          
drop and all, so it's quite,    
quite straightforward.          
And hopefully                   
it'll make sense.               
If you have any                 
questions about it,             
Piazza is a great place         
to ask. All right,              
let's go back to our slides     
and talk about UITextField.     
All right, UITextField it's     
a lot like UILabel and          
you might just think,           
it's just an editable UILabel.  
It's a little more complicated  
than that, but not much more.   
One thing to really think       
about conceptionally            
UITextField is having editable  
text fields, especially on      
the iPhone, is not a very good  
UI. And it's really easy to     
fall in the trap of throwing    
text fields into your UI and    
thinking, well, this is         
a great UI for doing this.      
Because you're running          
in the simulator and            
you gotta keyboard.             
You're just typing away         
in those text fields,           
hitting return, going to        
the next section, whereas,      
the poor user is like,          
my thumb's like,                
it's another dam text field,    
I hate them. So it's not        
a primary input source.         
If you can find a way to let    
them choose from a list or      
otherwise input the data        
without having to type things,  
it's better.                    
Now on the iPad it's not so     
bad, at least the keyboard      
is quite large,                 
it's much more accessible,      
people can put it down and      
use two hands. So it's not      
quite as bad on an iPad,        
but on an iPhone,               
don't get fooled.               
And I see a lot of you doing    
this in your final projects.    
You submit these projects to    
us that are just like, my god,  
this is almost unusable.        
Because we will be testing all  
your final projects             
on devices.                     
We won't be in the simulator    
and be able to type away.       
So think about that from your   
users, whether a text field's   
what you want. Once you've      
decided you want a text field,  
here's how it works. So a text  
field is something that,        
obviously, throws               
a keyboard up and               
lets you enter text. One thing  
to notice about the keyboard,   
is there's no keyboard          
object or anything,             
anywhere in iOS.                
So the keyboard coming up       
happens because an object       
becomes the first responder.    
So the first responder is the   
thing that gets the keyboard    
events from the keyboard. And   
as soon as something becomes    
first responder,                
it starts getting keyboard and  
the keyboard will appear, all   
right? So becomeFirstResponder  
is a message you can            
send to text field and          
it will cause it to be          
the first responder,            
which will cause                
the keyboard to come up. And    
similarly, if you send it       
resignFirstResponder it will    
stop being the first responder  
and the keyboard will go away.  
So that is how you make the     
keyboard come and go in iOS,    
is by making things become and  
resignFirstResponder. So        
that's important to             
understand about keyboards.     
One thing about text field      
that's totally different than   
the label,                      
is that it has a delegate.      
And that its delegate is the    
primary way you interact with   
the text field.                 
As supposed to a label,         
label don't even have           
a delegate. You just ask for    
its text and set its values     
and that's it. Whereas since    
a text field is editable, as    
things are being edited like    
a selections changing, or       
someone types something new,    
you can find out about all      
of those things going on.       
And another example is a lot    
of times in the keyboard,       
when the user hits the return   
key in the keyboard,            
you want the keyboard           
to go away, right? So,          
textFieldShouldReturn right     
there, is a method that gets    
called when the Return key is   
pressed. And inside there,      
you very likely wanna say,      
resignFirstResponder, and that  
will cause the keyboard to go   
away. So that's an example of   
what you can do with            
the delegate. Another really    
important delegate method       
is textFieldDidEndEditing.      
This gets called when it        
resigns first responder.        
So if someone is editing in     
your text field and they touch  
on another text field,          
you'll resign first responder.  
So if you wanna look at         
the text at that point,         
you're gonna wanna implement    
this delegate method.           
Now having said that,           
text field is a UI control.     
So it does have target          
action and you can control,     
drag it and have it send        
certain target action messages  
on certain activities           
happening in the text field.    
And some time people hook it    
up that way without doing       
the delegate thing.             
But you kinda                   
need to know this delegate      
because you need to know what   
it's capable of doing. So       
you'll definitely wanna look    
up the UITextField Delegate     
protocol, and see what are all  
the things you can find out     
about what's happening when     
editing is happening in         
a text field. All right,        
the keyboard, so since there's  
no keyboard object in iOS,      
what if you want to             
configure the keyboard like,    
set what,                       
whether it does autocorrect.    
Right, how it does all          
that annoying autocorrect?      
I didn't say annoying.          
It does autocorrect and         
you don't want it to do that    
because it doesn't make sense   
in your text field,             
you can turn that off. But      
you do all that by talking to   
the text field, not by talking  
to the keyboard. Anybody who    
puts up a keyboard is going to  
implement this protocol         
called UITextInputTraits, and   
it has all these                
keyboard activities. And        
it's that guy's responsibility  
to get the keyboard to do       
the right thing.                
The keyboard also has in the    
text input traits protocol, it  
also has input accessory view   
which lets you put a little     
view on the keyboard, right at  
the top of the keyboard. So if  
you had some special buttons    
or something you want, you can  
put them in there, so that's    
kinda cool, all right? Now,     
one thing, I'm not gonna even   
talk about this slide yet, but  
later in the quarter, I will.   
But I'm putting it up here for  
reference, you can go back and  
look at it. It's important to   
understand that when            
the keyboard comes up,          
it covers up your views,        
right? The keyboard does not    
move things out of the way      
normally, it comes up.          
Now, there are some classes     
like the UITableViewController  
bundle, right, the thing that   
you can drag out and get        
a whole UITableViewController   
with the table view,            
that does. That will scroll     
things up out of the way        
of the keyboard. But normally,  
the keyboard just comes up,     
and your stuff is behind it.    
And I'll tell you another huge  
problem with final projects is  
people who've only run them     
in the simulator, and           
when you run on a device and    
you press on a text field,      
the keyboard comes up and       
covers that text field. And     
so you can't even enter any     
information in that text        
field. That's extremely common  
and we will, basically, not     
be able to test certain parts   
of your app because we can't    
even type in, to a text field.  
So it is your responsibility    
to move things out of the way.  
Now, when I talk                
about NSNotification,           
hopefully next week,            
I will tell you how to find     
out that the keyboard has       
come up, where its come up.     
And then you can                
react by moving                 
your UI out of the way,         
hopefully by scrolling it in    
scroll view, but you might      
have to do it some other way.   
There's a lot of other stuff    
in text field, you can look in  
the documentation for. You've   
already seen like the auto      
shrink of UI label. Text        
field has that as well and      
you can control it like         
setting the minimum font size,  
and stuff like that. When       
you click in the text field,    
do you want it to clear out     
the text that used to be in     
there and start afresh?         
Or do you want it               
to leave the text that          
used to be in there?            
Those kinds of things, you      
can do all that. It has some    
little accessory views that     
you can put on the left and     
right. It is a pretty           
powerful little object. So      
coming up now is gonna be this  
demo, but again we have to get  
out of here because of          
this mid-term coming.           
So we'll be doing that, on      
Monday, your homework five is   
out, it's posted already. It's  
essentially to do your own      
collection view and             
table view, all right?          
With some drag and              
drop, of course, and            
with a little UI text field as  
well. If you wanna wait until   
I do the demo on Monday to      
do the text field part,         
it's a very minor part of the   
assignment, you could do that.  
You could just do the rest of   
the assignment. I know you all  
like to get started on your     
assignments early. But if you   
do your whole assignment        
before Monday, except for       
that, that's fine. And then     
on Tuesday you could work on    
the text field, it's not        
a huge part of the assignment.  
Again, no more Friday           
sections. And then next week,   
I'll be talking about the       
final project requirements,     
and we'll also be talking       
about persistence.              
We have this nice               
emoji art thing, but            
as soon as I quit my app and    
start it again,                 
I lost all my work. So we're    
gonna fix that next week and    
learn how to make things        
persist, between launching of   
the app. And that's             
a fairly small topic, so        
we'll actually be doing some    
other stuff as well next week.  
And then your                   
final assignment,               
assignment number six will      
probably go out next Wednesday  
and be due the next Wednesday.  
And then no more                
assignments the rest of the     
quarter because you'll have     
your final project. So your     
final project is a three week   
long thing, so you won't have   
any homework during the time    
you're working on your final    
project. All right? That's it.  
I will see you next Monday.     
For                             
more, please visit              
us at stanford.edu.             
