hey what's up everybody this is Ray and
today's screencast I'm going to
introduce you to a brand new feature in
iOS 11 the ability to add drag-and-drop
support into your apps the iPad comes
with nice multitasking support you can
run two apps side by side with the split
view feature or the slide over mode and
new this year iOS is out of the ability
to drag and drop items between apps this
is sure to be a huge time saver and
greatly desired by users and luckily
it's pretty easy to implement in this
screencast I'll show you how to add
drag-and-drop support to your iOS apps
I'll be showing you how to do this with
the table view in this screencast but if
you watch the screencast you'll also
understand how to do it with collection
views because it's pretty much the exact
same process just slightly different
api's I have a simple iPad app here
called pet finder that lists a batch of
pets up for adoption I'd like to add
drag-and-drop support into this app so
that I can drag the pets from the top
table view into the bottom table view
I'd also like to be able to drag and
drop two completely different apps for
example maybe I want to add a reminder
for a pet I'd like to adopt the first
step to adding drag and drop support is
to create a drag item object this
represents the item that you want to
drag which is a pet in our case a drag
item is a small wrapper around an item
provider you can think of the item
provider as the brains behind the
operation it knows how to convert your
item into different data formats for now
we're going to start simple and we'll
create an item provider that can export
our pet as a simple string with the name
of the pet I'll start by opening pets
data store dot Swift and import mobile
core services this is required to use a
UTI type enumeration that I'll need in a
moment next I'll make a helper method to
create they drag items for a given index
path first I'll look up the pet for the
given index path then I'll create an
empty NS item provider remember that a
UI drag item is just a simple wrapper
around an NS item provider which you can
think of as the brains behind the data
conversion task I'll then call
registered data representation passing
in the plain text UTI this is basically
saying hey this item provider supports
formatting
data is plain texts and here's a closure
to call whenever you want to format it
this way
note that this closure isn't called
right away it's only called when you
finish dragging the data somewhere and
wherever you drop it wants to receive
the data in this format once the drop
target requests the data in this plain
text format I'll then convert the pet's
name to a data buffer in utf-8 format
once I'm done I'll call the completion
handler now that I've created the NS
item provider I create a UI drag item
wrapper finally I return this as an
array now that we have this method it's
easy to conform to the protocol required
to add drag-and-drop support I'll open
pets view controller dot Swift and add
an extension to conform to the protocol
UI tableview drag delegate it has just a
single method to implement table view
items for beginning session at inside
this method I find the appropriate data
source using a helper method and then I
call the drag items method we just wrote
on that datasource finally inside
viewdidload right before table view
reload data I'll set the drag delegate
to self that's it I'll build and run and
note that if I tap and hold on an item
it starts dragging of course I can't
drop it in this app yet because I
haven't added drop support yet however I
can't drop it elsewhere
to show you this I'll slide up from the
bottom of the screen and drag reminders
over to the right and docket then I'll
drag Tiger over to reminders and nice it
accepts the drag and automatically adds
a reminder to the list at this point
we've implemented the method required to
add dragging support there was just one
required method to get the list of
dragged items remember that the dragged
item was just a wrapper around the item
provider which we provided with a
closure to convert the pet into a string
data format now let's implement the
delegate to provide dropping support
which has three required methods iOS
calls your first method to find out what
type of data your app accepts in our
case we'll just accept strings iOS then
calls your second method to find out
what you intend to do with that data as
the user drags the item around and in
our case we'll do different things based
on different situations between move
copy or cancel the third required
delegate method is called when the user
commits
the drop and in this case we'll go back
to the item provider and request the
data in string format let's see what
this looks like first I'll open Pet dot
Swift and add a helper method to
retrieve the types of objects that we
can accept the past in session object
has a method called can load objects
which you can use to see if the data
being dropped can be converted into a
target object type we're going to only
accept strings so we'll pass an nsstring
dot self here note that although we're
only accepting strings at the moment you
can accept multiple types of data if
you'd like that's what I'll be showing
you in the next screencast which covers
accepting multiple data representations
next I'll open pets view controller dot
Swift and add an extension for the
protocol required to accept dropping
data you by table do you drop delegate
we'll start with first required method
table view can handle this we'll simply
call the helper method that we just
wrote next I'll implement the second
required method table view drop session
did update with destination index path
basically this method lets you specify
what you intend to do with the drop data
either move it copy it or reject it
we'll be doing different things in
different cases first we'll see if the
user is dragging within the source table
if it is and they're dragging more than
one item we'll reject it by returning a
drop proposal of type cancel for this
app you can only move one item at a time
around the table view now here we know
that the user is dragging one thing
within our table view so we returned
that in this case we intend to move the
item from the old spots of the new spot
within the table view rather than copy
finally if we reach the else statement
then we know that we're receiving an
item that came from some other table
view and in this case we'll make a copy
of the data there's one required method
left table view perform drop with this
is the workhorse that does the drop
operation first we'll get the data
source for the table view that will
figure out where we should put the new
item if the coordinator gives us a
destination index path and great we'll
just use that but if it doesn't then
we'll create an index path to put it at
the end of the table
finally we loop through all of the items
that are dropped and processed each one
there are three cases we need to handle
first the item originated from the same
app in the same table view second the
item originated in the same app but a
different table view and third the item
originated from a different app let's
start with the final case as the other
two are optimizations
I'll put an if false temporarily so that
we can focus just on this final case for
now first I'll print a message out so we
can see what case rent while we're
debugging although eventually this will
be called only when we receive dated
route from a different app but remember
I put a if false in there for the other
cases so for now this will always be
called next I get a reference to the
item provider remember this is that
brainy object that can convert the data
you're dragging into different formats
then I use a helper method on the item
provider to load the data in the format
I want to accept and a string in this
case an S string is one of the objects
that implements the required protocols
for conversion along with NS attributed
string nsurl UI color UI image and MK
map item you can also make your own
objects conform to this protocol like
you'll learn in the next screencast I
then convert the string from an NS
string to a string I then create a pet
object given the name unknown for the
type and no image I then add the new pet
to our list of pets and the data source
and finally I update the table view with
table view insert rows making sure to
execute this on the main thread there's
one last thing back in viewdidload I'll
set the drop delegate to self oops I
have a typo here I typed index path but
meant to end at this point I can build
and run and check it out I can drag and
drop items from the reminders app into
my app I can also drag items between the
table views and the table view itself
but if I do this I lose data since
currently I'm only saving the name of
the pet out luckily there is an
optimization here that will fix that and
we'll do that next if you think about it
if you want to drag and drop within your
own app what we're doing right now is
kind of silly we already have the pet
object in memory so there's no need to
encode it into a limited utf-8 string
and then back again instead if it's in
the same table view we should simply
swap the rows and if it's within the
same
but a different table view then luckily
the dragon provides a handy local object
property that you can use to squirrel
away the pet later Hey
squirrels make great pets anyway let's
take a look let's fill in that first to
do if the item has the source index path
property set that means it's from the
same app and the same table view so I'll
call move item on the data source to
swap the positions then on the main
thread I'll perform a batch update to
delete the row of the source and insert
a row with the destination but what if
the item comes from the same app but a
different table to you well in that case
I'll open pets data source swift and in
drag items for right before I return the
array of the dragged item I'll set the
drag items local object to the pet I'd
like to transfer now back in pets view
controller dot Swift I could implement
the final to do if the local object is
set then I'll add it to the data source
directly and update the table view now
I'll build and run and check it out I
can move items within the table view
which works by swapping the rows as we
see in the console with the same app
same table view case I can also move
items to the completely different
adopted pets table view and it also
works we can see this works by copying
the pet we stored in a local objects
property as we can see in the console
with the same app different table view
case there's one last thing I want to
show you although in coding our string
into utf-8 format happens very quickly
sometimes when you're receiving data
from another app it may take a while to
do the conversion so when dropping an
item to a table view it's better to
insert a placeholder cell so the user
knows that the conversion is taking
place luckily this is a quick fix still
in pets view controller dot Swift inside
table view perform drop with and the
different app case I'll call a helper
method to add the placeholder cell I
need to pass in the dragged item the
destination path the identifier of the
cell to use and height and a handler to
update the cell I just set the text to
loading then once the item provider load
object closure completes I'll call
context commit insertion and pass in a
closure to update the data source
appropriately iOS will handle the table
view animations automatically
I'll build and run and if I drag a
string in from another app I see a brief
loading placeholder it's pretty quick
for this but it's a good practice for
when your data gets more involved all
right that's everything I'd like to
cover in this screencast at this point
you should know how to implement drag
and drop support into your iOS apps I've
shown you how to do this with table
views but now that you understand the
process you can do this exact same thing
the collection views if you prefer that
you might be curious how you can save
your data using multiple different
formats or how you can drag and drop
from custom views and that's what I'll
be covering at my next screencast I
promise it won't be a drag that's it for
this screencast
[Music]