
Drag & Drop mechanism, working in iOS 11 and iOS 12 , is a way to graphically asynchronously copy or move data both within one application and between different applications. Although this technology is about 30 years old, it has literally become a “breakthrough” technology on iOS due to the fact that when dragging and dropping something in iOS , multitouch allows you to freely interact with the rest of the system and collect data for resetting from different applications.iOS makes it possible to capture multiple items at once. Moreover, they do not have to be easily accessible for selection: you can take the first object, then go to another application and grab something else - all the objects will be collected in a “stack” under your finger. Then call the universal dock on the screen, open any application there and capture the third object, then go to the screen with applications running and, without releasing the objects, drop them into one of the open programs. Such freedom of action is possible on the iPad , on the iPhone , the range of Drag & Drop in iOS limited to the scope of one application.Safary , Chrome , IbisPaint X , Mail , Photos , Files , etc.) already have Drag & Drop . In addition, Apple provided developers with a very simple and intuitive API for embedding the Drag & Drop mechanism in your application. The Drag & Drop mechanism, like the gestures, works on UIView and uses the concept of “interactions” Interactions , which are a bit like gestures, so you can think of the Drag & Drop mechanism as just a really powerful gesture.API Drag & Drop improved and raised to a higher level of abstraction in the sense that the Collection View itself helps you with the indexPath of the collection item that you want to drag. Drag . It knows where your finger is and interprets it as the indexPath of a collection item that you are dragging Drag at the moment or as the indexPath of a collection item where you Drop something Drop . So the Collection View collection provides you with indexPath , but otherwise it’s absolutely the same API Drag & Drop as for a regular UIView .Drag & Drop process on iOS has 4 different phases:lift preview ) of the specified element is formed, and then the user begins to drag ( Dragging ) his fingers.
lift preview ) for this object can be modified (a green plus sign "+" or another sign appears) ...

Drag object will be destroyed, or the Drop object will be reset at the destination.
Drag & Drop mechanism into your iOS app.Collection View collection with the ability to fill ourselves with images OUTSIDE, as well as reorganize the elements INSIDE yourself using the Drag & Drop mechanism. In addition, this mechanism will be used to reset unnecessary elements of the Collection View into a “trash can”, which is a common UIView and is represented by a button on the navigation bar. We can also share images from other applications, such as Notes or Notability or Mail or the Photo Library ( Photo ), using the Drag & Drop mechanism.Drag & Drop mechanism in the demo application “Gallery of Images”, I will briefly go through its main components.UI ) of the Image Gallery application is very simple. This is the “screen capture” Image Gallery Collection View Controller inserted into the Navigation Controller :
Image Gallery Collection View Controller , which is supported by the ImageGalleryCollectionViewController class with the Image Gallery Model as a variable var imageGallery = ImageGallery () :
URL url of the image location (we are not going to store the image itself) and its aspect ratio aspectRatio :

subclass ImageCollectionViewCell of the UICollectionViewCell class:
Public API of the ImageCollectionViewCell class is the imageURL image URL . As soon as we install it, our UI updated, that is, the data for the image on this imageURL is selected asynchronously and displayed in a cell. While data is being sampled from the network, the spinner activity indicator is working, indicating that we are in the process of retrieving data.
memory cycle )?” We don’t have an explicit “cycling memory reference” ( memory cycle ), because self itself does not have a pointer to this closure.Collection View collection are reusable thanks to the dequeueReusableCell method. Each time a cell (new or reused) hits the screen, the image is launched asynchronously from the network (the spinner of the spinner activity indicator is spinning at this time).UI this collection cell is updated. But we don’t wait for the image to load, we continue to scroll through the collection and the collection cell that we’ve noticed goes off the screen without updating our UI . However, a new image should appear from below, and the same cell that has left the screen will be reused, but for another image, which may load quickly and update the UI . At this time, the image download previously launched in this cell will return and the screen will be updated, which will lead to an incorrect result. This is because we are running different things working on the network in different threads. They return at different times.URL url that caused the download of this data and compare it with what the user wants to have in this cell at the moment, that is, imageURL . If they do not match, then we will not update the UI cell and wait for the image data we need:
Collection View can confuse the user a bit:

Controller so that it corrects the aspect ratio of its aspectRatio for the corresponding indexPath in its ImageGallery model . This is an interesting task, there are many ways to solve it, and we will choose the easiest of them - using Optional closure var changeAspectRatio: (() -> Void)? . It can be nil and need not be installed if there is no need for it:
Controller in the cellForItemAt method:

Collection View image Collection View , on our UI we placed the Bar Button with a custom GarbageView image, containing the “trash can” as a subview on the navigation bar:

Bar Button Trash button:


Github in the ImageGallery_beginning folder. If you launch this version of the Image Gallery application, you will see the result of the application’s work on the test data, which we will subsequently delete and fill in the Image Gallery only OTHER:
Drag & Drop mechanism in our application is as follows:Collection View ability to drag Drag UIImage from outside both locally and from it,Collection View images to take drag-drawn Drag from outside or locally UIImage images,Collection View and remove them from the Collection View collection.Drag & Drop mechanism implemented. It is located on Github in the ImageGallery_finished folder.Drag & Drop mechanism in your Collection View ensured by two new delegates.Drags .Data transfer ) and custom animation settings for Drop , as well as other similar things.Drag dragging or Drop , but you can use both protocols at the same time and drag Drag and drop Drop , which opens up additional functionality. Drag & Drop mechanism for changing the order of elements in your Collection View .Drag Elements From Collection ViewDrag protocol is very simple, and the first thing you should always do is install yourself, self , as a delegate to dragDelegate :

Fix button:
Drag system WHAT we are dragging. The itemsForBeginning method is called when the user starts dragging a cell of the cell collection.Collection View added an indexPath to this method. This will tell us which element of the collection, which indexPath , we are going to “drag”. This is really very convenient for us, since it is up to the application to take responsibility for using the session and indexPath arguments to figure out how to handle this Drag dragging.Drag dragging is initialized; if the empty array [] is returned, the Drag dragging is ignored.
Drag & Drop operation is completely asynchronous. When you start Drag dragging, it’s really a very lightweight object ( lift preview ), you drag it everywhere, and nothing happens during that dragging. But as soon as you “drop” Drop your object somewhere, then being an ItemProvider , you really should supply your “dragged” and “thrown” object with real data, even if it takes a certain amount of time.iOS and that are itemPoviders , such as NSString , for example, which allows you to drag text without fonts. Of course, this is a UIImage image. You can select and drag UIImages everywhere. NSURL class, which is absolutely wonderful. You can go to the Web page, select the URL and “throw” it wherever you want. This may be a link to the article or the URL for the image, as it will be in our demo. These are the color classes of UIColor , the MKMapItem map element , the CNContact contact from the address book, a lot of things you can select and drag. All of them are itemProviders .Collection View cell with the indexPath , which helps me to select a cell , get an Outlet imageView from it and get its image .Collection View about the cell cell for the item element corresponding to this indexPath .
Collection View only works for visible ( visible ) cells, but, of course, it will work in our case, because I’m dragging the Drag item on the screen and it is visible.subclass . And if it works, then I get an Outlet imageView , from which I take its image . I just captured the image image for this indexPath .


Draglocally, that is, inside your application, then you do not need to go through all this code associated with itemProvider , through asynchronous data retrieval. You do not need to do this, you just need to take localObject and use it. This is a kind of “short circuit” with a local “drag and drop” Drag.Dragbeyond our collection Collection Viewto other applications, but if we “drag and drop” Draglocally, we can use localObject . Next, I return an array consisting of a single dragItem element .Dragis canceled.
Dragsession session . In our case, it will be a collectionView collection.and it is useful to us afterwards:
Drag, you can add more items items to this "drag and drop", just doing the gesture tap on them. As a result, you can drag a Draglot of items at once. And it is easy to implement using another method delegate UICollectionViewDragDelegate , very similar to the method itemsForVeginning , a method called itemsForAddingTo . The itemsForAddingTo method looks exactly the same as the itemsForVeginning method , and returns exactly the same thing, because it also gives us the indexPathof what the user “tapped” on during the “drag Dragand drop” process , and it is enough for me to get an image from the cell where the user “tapped” and return it.
Drag.
Photos, as you see a green plus sign "+" in the upper left corner of the "drag and drop" image. I can perform a tap gesture on one more image of "Artik" from the collection Collection View...
Photos:
Photoshas a mechanism already built in Drag & Drop, everything works fine, and this is cool.Dragand “reset” the DropGallery image to other applications, I did not have to do much in my application, except for the delivery of the image as an array [UIDragItem] . This is one of the many great features of the mechanism.Drag & Drop - it is very easy to make it work in both directions.Dropimages In a collectionCollection ViewDroppart for my collection Collection Viewso that we can “drop” Dropany “draggable” images INSIDE of this collection. “Dragged” image can “come” both from outside and directly from inside of this collection.

Fix, and before us appear the mandatory methods of this protocol. In this case, we are told that we must implement the performDrop method :
Drop. In fact, I'm going to implement the performDrop method last, because there are a couple of other highly recommended Applemethods that need to be implemented for the Droppart. These are canHandle and dropSessionDidUpdate :
ollection View, and besides, we will not try to dump something we do not understand.ollection View. But this method ollection Viewlooks exactly the same as a similar method for a regular UIView , there is no indexPath . We just need to return session.canLoadObjects (ofClass: UIImage.self) , which means that I accept the “reset” of the objects of this class PAS in my collection ollection View:
Dropimage into my collection Collection ViewOUTSIDE.Dropimage is dumped INSIDE a collection Collection View, when a user reorganizes his own elements of items using a mechanism Drag & Drop, then a single UIImage image is enough , and the implementation of the canHandle method will look like this.Dropimage “dumping” happens EXTERNAL, then we need to process only those “drag and drop” Dragthat represent the UIImage image along with URLfor this image, since we are not going to store the UIImage images directlyin the model. In this case, I will return true in the canHandle method only if a pair of session.canLoadObjects conditions (ofClass: NSURL.self) && session.canLoadObjects (ofClass: UIImage.self) are simultaneously executed & :
Dropthe session the session , both its local Dragsession localDragSession . This local Dragsession in turn has a local context localContext .Drag delegate UICollectionViewDragDelegate :

DropEXTERNAL.Dragonto our collection Collection View. Otherwise, it doesn’t make sense at all to talk about “dumping” Drop.Drop, then even before the user lifts his fingers from the screen and a real “reset” occurs Drop, we must inform the delegate UICollectionViewDropDelegate about the UIDropProposal proposal to perform a reset iOSusing the dropSessionDidUpdate method .DropDropclause that can have the values .copy or .move or .cancel or .forbidden for the operation argument . And these are all the possibilities that we have in the usual case when dealing with the usual UIView .Collection Viewgoes further and offers to return the specialized UICollectionViewDropProposal clause , which is subclassof the UIDropProposal class and allows, in addition to the operation operation, to specify an additional intent parameter for the collection Collection View.Collection Viewwhether we want the “reset” element to be placed inside an already existing cell or whether we want to add a new cell. See the difference? In the case of a collection,Collection Viewwe must report our intent intent .

Collection Viewwith this small piece of information that we provided to it.Safariwith a search engineGoogle, and this image has a green "+" sign on top, indicating that our Gallery of Images is ready not only to receive and copy this image along with it URL, but also to provide a place inside the collection Collection View:
Safari, and “Dragged” images will already be 3:
Dropthese images, they will not be placed in our Gallery, but will simply return to their former places, because we have not yet implemented the performDrop method .
Collection Viewalready knows what I want to do.Collection Viewis absolutely wonderful thing for the mechanism.Drag & Drop, it has very powerful functionality for this. We barely touched it, having written 4 lines of code, and it already advanced far enough in the perception of “reset” Drop.
Drop, then in the performDrop method we have to update our Model, which is imageGallery Image Gallery with a list of images images , and we need to update our collectionView visual collection .Drop.Dropfrom my collectionView , then I need to “reset” the Dropcollection item at the new location and remove it from the old location, because in this case I move ( .move ) this collection item. This is a trivial task. IfDropfrom another application, we must use the itemProvider property of the “drag and drop” item element to select data.Dropin the collectionView collection , the collection provides us with the coordinator coordinator. The first and most important thing that the coordinator coordinator tells us is the destinationIndexPath , that is , the destination-point indexPath of the “reset” Drop, that is, where we will be “reset”.
Collection Viewthat is not between any existing cells , so that it may well be nil . If this is the situation, then I create an IndexPath with the 0th item element in the 0th section of the section .
Drop. We must go through all the “reset” elements of coordinator.items provided by the coordinator coordinator . Each item from this list has the UICollectionViewDropItem TYPE and can provide us with very interesting pieces of information.Dragis done from myself, self, and the source of the drag Dragis the collection item with the indexPath equal to sourceIndexPath :
Drag & Drop , and the task becomes trivial. All I need to do is update the Model so that the source and destination point are swapped, and then update the collectionView collection to remove the collection item from sourceIndexPath and add it to the collection from destinationIndexPath .Drag & Dropworks not just in the same application, but also in the same collectionView collection , and I can get all the necessary information using the coordinator coordinator. Let's implement this simplest local case:
Dropimages into the “trash can”, which is in the same application, but is not the same collectionView collection . Now two IndexPathes are enough for me : the source sourceIndexPath and the destination point destinationIndexPath .
Drag, because it resets the whole "world" of our gallery of images, which is very bad, I do not. Instead, I'm going to remove and insert items.items separately:
closure) and within that closure I can place any number of these deleteItems , insertItems , moveItems and all I want:
Drop:



Dragand drop” EITHER and “drop” "DropDoes this information become available instantly? No, you select data from the “dragged” thing ASYNCHRONOUS. But what if the sample takes 10 seconds? What will the collection do at this time ollection View? In addition, the data may not come at all in the order in which we requested it. To manage this is not at all easy, and in this case it Appleproposed a ollection Viewcompletely new technology for using substitutes Placeholders.Collection Viewsubstitute in your collection Placeholder, and the collection Collection Viewmanages it all for you, so all you have to do when the data is finally selected is to ask the substitute to Placeholdercall its context placeholderContextand inform him that you received the information. Then update your Model and the context of the placeholderContext AUTOMATICALLY swap a cell cell with a placeholder Placeholderfor one of your cells cells , which corresponds to the type of data you received.Placeholderand which you get from the coordinator coordinator by asking to “reset” Dropthe item element on the placeholder Placeholder.
Dropis item.dragItem , where item is the for element of the loop, since we can “throw” Dropmany coordinator.items objects . We “throw” them one by one. So item.dragItem is what we “drag” Dragand “throw” Drop. The next argument to this function is the placeholder, and I will create it using the initializer UICollectionViewDropPlaceholder :
Placeholder, that is, insertionIndexPath , as well as the reuseIdentifier cell identifier .Placeholder. The coordinator coordinator does not have a “pre -assembled ” cell for the locator.Placeholder. It is YOU who must decide on this cell . Therefore, a reuse cell identifier reuseIdentifiercell is requested with yours storyboardso that it can be used as a PROTOTYPE.storyboardto create this thing.storyboardand create a cell cell for the placeholder Placeholder. To do this, we just need to select a collection Collection Viewand inspect it. In the very first field, ItemsI change 1to2. This immediately creates a second cell for us, which is an exact copy of the first one.
ImageCell, set the identifier “ DropPlaceholderCell”, remove all UIelements from there , including Image View, since this PROTOTYPE is used when the image has not yet arrived. Add a new activity indicator from the Objects Palette Activity Indicator; it will rotate, making it clear to users that I am expecting some “discarded” data. Also change the background color Backgroundto understand that when "Reset" from the outside image works exactly this cell cell as prototypes:
Outletscontrol:
Activity Indicatorso that it starts animating from the very beginning, and I wouldn’t have to write anything in the code to run it. To do this, click on the options Animating:
DropPlaceholderCell, go back to our code. Now we have an excellent replacement locator Placeholder, ready to go .Placeholderand our “native” data cell, and we will make changes in the Model.
main queue. And, unfortunately, we had to switch to main queueusing DispatchQueue.main.async {} in order to “catch” the aspect ratio of the image in the local variable aspectRatio .


Placeholderwith a cell by calling the normal cellForItemAt method .Collection Viewcan very much happen. New cells can be added cells , everything happens fairly quickly.
URLimage imageURL from the corresponding by provider , an error might have been received error instead by provider , we have to let them know the context placeholderContext , you need to destroy this a placeholder Placeholder, because we are all the same, we can not to get other data:
URLsthat comes from places like Google, in fact, they need minor transformations to get a “clean”URLfor the image. How this problem is solved can be seen in this demo application in a file Utilities.swifton Github .URLimage, we use the imageURL property from the URL class :
Collection View.ImageGalleryand Safariwith a search engine Google. In Googlewe are looking for images on the theme "Dawn" (sunrise). In Safarialready builtDrag & Dropmechanism, so we can select one of these images, hold it for a long time, move it a little and drag it to our Gallery of Images.
Placeholder:
Placeholderdisappears:

Placeholder:


Controller Dragand Dropdelegate and add the pinch gesture recognizer , which controls the number of images on the line:

Dropin the performDrop method ...




Placeholderworks ...


Placeholdersworking ...

Dropin the trash can presented on the navigation bar on the right. As described in the “Image Gallery” demo application features section, the trash can is represented by the GabageView class , which inherits from UIView, and we have to teach it to take images from our collection ollection View.DropGallery images into the trash can.Drop

DropsessionDidUpdate and performDrop .
Collection View, we do not have any additional information in the form of the drop- point indexPath .Drag, which are UIImage images. Therefore, I will return true only if session.canLoadObjects (ofClass: UIImage.self) :
Drop . And I am ready to accept only the “drag and drop” LOCALLY object of the UIImage image TYPE , which can be “dumped” Dropanywhere inside my GarbageView . My GarbageView will not interact with images dumped EXIT. Therefore, I analyze using the variable session.localDragSession, whether there is a local “drop” Drop, and return the “reset” clause in the form of the UIDropProposal constructor with the operation argument set to .copy , because ALWAYS LOCAL drag and drop Dragin my application will come from the collection Collection View. If there is a “drag Dragand drop” and “reset” DropOUTSIDE, then I return the “reset” clause in the form of the UIDropProposal constructor with the operation argument set to .fobbiden , that is, “forbidden” and we will get the sign of the “reset” prohibition instead of the green plus sign .
Collection View.Dropto another place and at the same time transforming the “discarded” object during animation:

Drop, and I (like GarbageView ) receive the message performDrop . In the message performDrop we perform the actual "reset" Drop. Honestly, the image itself, discarded on the GarbageView , no longer interests us, since we will make it almost invisible, most likely the fact that the “reset” is complete Dropwill signal that we remove this image from the collection Collection View. In order to do this, we need to know the collection itself and collection and indexPathdumped image in it. Where can we get them from?Drag & Droptakes place in a single application, it is available to us all the local: local Dragsession localDragSession our Dropsession the session , the local context localContext , which is our collection of sollectionView and local object localObject , which we can do by itself is reset image image from "Gallery" or indexPath . Because of this we can get in the method performDrop class GarbageView collection collection , and using itdataSource how ImageGalleryCollectionViewController and Model imageGallery ourController, we can get an array of images of images TYPE [ImageModel]:
Dragsession localDragSession ourDropsession session we were able to get all the "drag" on GarbageView Drag elements of items , and there may be a lot, as we know, and all of them are images of our collectionView collection . Creating theDragelements ofour collection's dragItemsCollection View , we provided for each “overtightened”Dragelement.dragItem local object localObject , who is the image of image , but it is we do not come in handy during internal reorganization collection CollectionView , but the "reset" Image Galleries "trash can" we desperately need in the local facility localObject "drag" object dragItem , after all this time we do not have a coordinator coordinator who so generously shares information about what is happening in the collectionView collection . Therefore, we want the local object localObject to be the indexPath in the image array images of our ModelimageGallery . Make the necessary changes in the method dragItems (at indexPath: IndexPath) class ImageGalleryCollectionViewController :






Collection View, hiding in the "garbage can":
JSONformat. To do this, we add var defailts ... ... to our Controllervariable , and the Codable protocol in the ImageGallery and ImageModel structures : String strings , Array , URL and Double arrays already implement the Codable protocol , so we don’t have to do anything else to make the encoding work and decoding for the ImageGallery model in the format.

JSONJSONversion of ImageGallery ?JSONformat:
JSON, or nil if this conversion cannot be performed, although the latter never happens because this TYPE is 100% Encodable . The Optional json variable is used simply for symmetry reasons.JSON. At the same time json variable has TYPE Data? which can be memorized in UserDefaults .JSON data , and I would like to recreate our Model, an instance of the ImageGallery structure, from them . To do this, it is very easy to write an INITIALIZER for ImageGallery , whose input argument is json data . This initializer will be a “falling” initializer (JSONfailable). If it fails to initialize, then it “falls” and returns nil :
fail), because it is quite possible that the jsonJSON datamay be corrupted or empty, all of which can lead to the “fall” ( fail) of the initializer.JSONdata and recovery model imagegallery the method viewWillAppear our Controller...


Drag & Dropin an iOSapplication. This allowed us to fully edit the Gallery of Images, "throwing" there new images from other applications, moving existing ones and removing unnecessary ones. And also distribute images accumulated in the Gallery to other applications.Files. It allows you to create UIDocument documents of the “Gallery of Images” type both on your iPadand on iCloud Drive, as well as select the necessary document for viewing and editing.Drag & Dropand after is on Github .Source: https://habr.com/ru/post/425817/
All Articles