!(https://hackernoon.com/hn-images/1*3IIeDZy7NnarO_zPWahEag@2x.png)\n\nWith the release of **iOS-11**, Apple introduced **Drag and Drop** in `UITableView` and `UICollectionView` with a specialized API that works on the concept of **Interactions** (something like gestures).\n\nTable view and collection view have similar APIs to support drag and drop with some small differences.\n\nDrag and drop is supported in both **iPhone** as well as **iPad**. On iPad, user can drag-drop within multiple apps. But for iPhone this support is provided only within a single app.\n\nWe’ll be discussing how drag and drop works in collection views and the same will be applicable to table views. I’ll point out the differences in table view wherever required. So don’t worry about it. You’ll get it working for both collection view as well as the table view.\n\n### Let’s get started 🚀\n\nAdopting drag and drop in collection view is a multi-step process. We’ll go through each and every detail required to integrate dragging and dropping elements in the collection view.\n\n#### UICollectionViewDragDelegate\n\nTo enable **drags**, the custom object must conform to `[UICollectionViewDragDelegate](https://developer.apple.com/documentation/uikit/uicollectionviewdragdelegate)` protocol.\n\nIt contains multiple methods that can be implemented to customize the drag behaviour of the collection view.\n\nThe only **required method** of this protocol you need to put in place to support drag behaviour is:\n\n[collectionView(\\_:itemsForBeginning:at:)](https://developer.apple.com/documentation/uikit/uicollectionviewdragdelegate/2897389-collectionview)\n\nWe’ll look into the method details in upcoming sections.\n\nAlso, set the `dragDelegate` delegate object of collection view in `viewDidLoad()` to manage the dragging of items from it.\n\ncollectionView.dragDelegate = self\n\n#### UICollectionViewDropDelegate Protocol\n\nTo enable **drops**, the custom object must conform to `[UICollectionViewDropDelegate](https://developer.apple.com/documentation/uikit/uicollectionviewdropdelegate)` protocol.\n\nThe only **required method** of this protocol is:\n\n[collectionView(\\_:performDropWith:)](https://developer.apple.com/documentation/uikit/uicollectionviewdropdelegate/2897304-collectionview)\n\nYou can implement other methods as needed to customize the drop behavior of your collection view.\n\nAlso, assign your custom delegate object to the `dropDelegate` property of your collection view in `viewDidLoad()`.\n\ncollectionView.dropDelegate = self\n\n#### Enabling Drag Interaction\n\nTo enable/disable drags , you can customize `dragInteractionEnabled` property of your collection view.\n\nThe default value of this property is true on iPad and false on iPhone.\n\nSo, set it to **true** to enable content dragging from your collection view if you are providing drag-drop support in iPhone.\n\ncollectionView.dragInteractionEnabled = true\n\n#### Dragging a Single Item\n\nNow that we have configured our collection view to support drags and drops, its time to actually write the code that will make it happen.\n\nLet’s start with the introduction to some important classes required to support drags and drops. Here we go:\n\n1. [NSItemProvider](https://developer.apple.com/documentation/foundation/nsitemprovider) **—** An item provider for conveying data or a file between processes during drag and drop.\n2. [UIDragItem](https://developer.apple.com/documentation/uikit/uidragitem) **—** A representation of an underlying data item being dragged from one location to another.\n\nEach item that needs to be dragged must be represented as an object of `UIDragItem`.\n\nTo allow dragging of items from your collection view, implement the only required method of `UICollectionViewDragDelegate` and return one or more `UIDragItem` objects for the item at the specified `indexPath`.\n\nOMG ! 😯 What was that? Too much to understand..!!!\n\nDon’t worry. We’ll go through each step in the below code:\n\n!(https://avatars1.githubusercontent.com/u/22985285?s=400&v=4)\n\nLet’s see what the code says..\n\n1. Line 1 — implement the`collectionView(_:itemsForBeginning:at:)` method of `UICollectionViewDragDelegate` .\n2. Line 3 — Get the data corresponding to the picked item’s `indexPath` . Use the model that you are using as collection view’s data source. \n Here I have used an array of `String` objects as the data source to the collection view. So, item will correspond to a `String` value.\n3. Line 4 — Create an object of `NSItemProvider` using the `item` extracted in Line 3. `item` is casted into `NSString` because `**NSItemProvider**` **accepts an object** and swift `String` is a value-type not an object-type.\n4. Line 5 — Create a `UIDragItem` object from `itemProvider`.\n5. Line 6 — `localObject` is the custom object associated with the drag item. It is only available to the app that initiates the drag activity. \n This is **optional** but makes it faster to drag and drop content within the same app.\n6. Line 7 — Return an **array** of `dragItem` .\n\nIn case you want to ignore the drag, return an empty array.\n\n#### Dragging Multiple Items\n\nWe have seen how to drag a single item from collection view. What if I want to drag multiple items in one go?\n\nWell, we have a `UICollectionViewDragDelegate` method to achieve that.\n\n[collectionView(\\_:itemsForAddingTo:at:point:)](https://developer.apple.com/documentation/uikit/uicollectionviewdragdelegate/2897367-collectionview)\n\nThis method adds the specified items to an existing drag session.\n\nItems are added to the active drag session with a **single tap**. If you do not implement this method, taps in the collection view trigger the selection of items or other behaviors.\n\nIt has the similar implementation as that of `collectionView(_:itemsForBeginning:at:)` .\n\n!(https://avatars1.githubusercontent.com/u/22985285?s=400&v=4)\n\nYou can add your own constraints as per your requirement.\n\n**Example**: ignore adding the item if it already exist in collection view in which you are dropping it. In this case return an empty array.\n\n#### Drop Proposal — UICollectionViewDropProposal\n\nWe picked the item and then dragged it. Now, we cannot just keep on dragging the item for long. What to do with it now? Where to drop it? What will happen when I drop the item?\n\nAll of these questions point to a very specific one : \n “How do you intend to handle the drop at a specified location? \nDo you want to copy the item or just move it to a new position? \nOr do you want to forbid the movement in some specific conditions? \nOh no..!! Can I just cancel it?”\n\nWell well well..!!! There is a single answer to all your question — **Drop Proposal.** A drop proposal as the name suggests is the proposal of how you intend to handle the drop at a specific location when the user lifts his finger.\n\n[UIDropProposal](https://developer.apple.com/documentation/uikit/uidropproposal) — A configuration for the behavior of a drop interaction, required if a view accepts drop activities.\n\nEach proposal defines an **operation** — [enum UIDropOperation](https://developer.apple.com/documentation/uikit/uidropoperation), that determines how a drag and drop activity resolves when the user drops a drag item. An operation is defined by can be of type:\n\n1. `cancel` — no data should be transferred, canceling the drag.\n2. `forbidden` — although a move or copy operation is typically legitimate in this scenario, the drop activity is not allowed.\n3. `copy` — data represented by the drag items should be copied to the destination view.\n4. `move` — data represented by the drag items should be moved, not copied.\n\n[UICollectionViewDropProposal](https://developer.apple.com/documentation/uikit/uicollectionviewdropproposal) — A subclass of UIDropProposal dedicated to collection views for handling drop proposals.\n\nA collection view proposal also defines an optional **intent** — [enum UICollectionViewDropIntent](https://developer.apple.com/documentation/uikit/uicollectionviewdropintent), that determines how to incorporate the content into the collection view. You can insert the content between items or add it to an existing item. Possible values of an intent are:\n\n1. `unspecified` — No drop proposal was specified.\n2. `insertAtDestinationIndexPath` — Insert the dropped items at the specified index path.\n3. `insertIntoDestinationIndexPath` — Incorporate the dropped items into the item at the specified index path.\n\nThe collection view uses `intent` information to provide appropriate **visual feedback** to the user.\n\nNow that we know what a drop proposal is, the thing we need to figure out now is how and where to implement it.\n\n`UICollectionViewDropDelegate` provides a method where you can specify the drop proposal you want to use, that is:\n\n[collectionView(\\_:dropSessionDidUpdate:withDestinationIndexPath:)](https://developer.apple.com/documentation/uikit/uicollectionviewdropdelegate/2897375-collectionview)\n\nWhile the user is dragging content, the collection view calls this method repeatedly to determine how you would handle the drop if it occurred at the specified location.\n\nBecause this method is called repeatedly while the user drags over the collection view, **your implementation should return as quickly as possible**.\n\n!(https://avatars1.githubusercontent.com/u/22985285?s=400&v=4)\n\nIn the above code I have used 2 properties:\n\n1. [localDragSession](https://developer.apple.com/documentation/uikit/uidropsession/2890985-localdragsession) — The local drag session is `nil` if the drag activity started in a different app.\n2. [hasActiveDrag](https://developer.apple.com/documentation/uikit/uicollectionview/2897415-hasactivedrag) — A Boolean value indicating whether items were lifted from the collection view and have not yet been dropped.\n\nSo here is what the above code speaks:\n\n1. Line 16 — If the drag activity started in another app, **forbid** the drop.\n2. Line 7 — Else, if the item was lifted from the same collection view in which you are dropping it, then **move (reorder)** it from source to destination index path.\n3. Line 11 — Otherwise, if you are dropping it in another collection view, then **copy** the item to the destination index path.\n\n#### Handling Drop — Copy\n\nAfter being clear about how we intend to handle the drop, let’s look at the implementation details of what we need to do once the actual drop is made.\n\nTo allow dropping of items in your collection view, implement the only required method of `UICollectionViewDropDelegate`.\n\nThat is: \n`collectionView(_:performDropWith:)` — Tells your delegate to incorporate the drop data into the collection view.\n\nThis method provides you with a [UICollectionViewDropCoordinator](https://developer.apple.com/documentation/uikit/uicollectionviewdropcoordinator) object that you can use to handle the drop. Using `coordinator`, you can fetch the below items to update your collection view’s data source:\n\n1. `items` — The items being dragged\n2. `destinationIndexPath` — The index path at which to insert the item in the collection view. It is an **optional** value. `nil` is returned in case the item is inserted in an empty collection view or at the end of the collection view.\n3. `proposal` — The current proposal for how to incorporate the dropped items\n\nAlso, when incorporating items, use `drop(_:to:)` or `drop(_:toItemAt:)` methods of the `coordinator` object to animate the transition from the drag item's preview to the corresponding item in your collection view.\n\nLet’s look at some code now.\n\n!(https://avatars1.githubusercontent.com/u/22985285?s=400&v=4)\n\nThe above code is pretty straight forward:\n\n1. `destinationIndexPath` is fetched from the `coordinator` . In case it is `nil`, the last index path of the collection view is used as the destination to drop the item.\n2. Take appropriate action to update the collection view based on the drop proposal’s `operation` — `move/copy/forbidden/cancel`.\n\nIn case your drop proposal is `**cancel/forbidden**`, `collectionView(_:performDropWith:)` won’t be called for handling the drops and hence you need not do anything special about it.\n\nIf the proposed handling is `**move**` , we need to reorder the items. We’ll discuss more about reordering in the next section.\n\nIn this section, let’s have a look at how to handle drop if we intend to `**copy**` the items.\n\nYou can use collection view’s `[performBatchUpdates(_:completion:)](https://developer.apple.com/documentation/uikit/uicollectionview/1618045-performbatchupdates)` to make changes in the collection view.\n\nYou can use this method in cases where you want to make multiple changes to the collection view in one single animated operation, as opposed to in several separate animations.\n\nDeletes are processed before inserts in batch operations. This means the indexes for the deletions are processed relative to the indexes of the collection view’s state before the batch operation, and the indexes for the insertions are processed relative to the indexes of the state after all the deletions in the batch operation.\n\nHere is how you can do it:\n\n!(https://avatars1.githubusercontent.com/u/22985285?s=400&v=4)\n\nTo get the data corresponding to dragged item, you can use one of the below options:\n\n1. `localObject` property of the drag item can be used if it is set. It will be available if the content is originated from elsewhere in your app.\n2. Also, you can use the drag item’s `itemProvider` property to fetch the data.\n\n#### Handling Drop — Reordering\n\nReordering of the cells occur when the drop proposal is specified as — **move**.\n\n**Reordering** — Moving an item from source index path to destination index path within same/different collection view or table view as per your requirement.\n\nI am explicitly referring to table view here because table view and collection view handle reordering a bit differently. We’ll discuss both of them here.\n\n**In table views**, reordering functionality is already available since a long time. And the good thing is we can continue using that 😅. No need to do anything special to support reordering in table views. You just need to:\n\n1. Return `move` as your drop proposal in `[tableView(_:dropSessionDidUpdate:withDestinationIndexPath:)](https://developer.apple.com/documentation/uikit/uitableviewdropdelegate/2897302-tableview)` to support reordering.\n2. Implement `[tableView(_:canMoveRowAt:)](https://developer.apple.com/documentation/uikit/uitableviewdatasource/1614927-tableview)` and `[tableView(_:moveRowAt:to:)](https://developer.apple.com/documentation/uikit/uitableviewdatasource/1614867-tableview)` methods of `UITableViewDataSource`.\n\n!(https://avatars1.githubusercontent.com/u/22985285?s=400&v=4)\n\n`[tableView(_:performDropWith:)](https://developer.apple.com/documentation/uikit/uitableviewdropdelegate/2897427-tableview)` won’t be called for handling drops if the above `UITableViewDataSource` methods are implemented.\n\n**In collection views**, reordering is handled in the same manner as copying. The only difference is — **in copying** you were inserting a brand new item at the destination index path, but **in reordering** you need to delete an item from source index path and insert it at the destination index path.\n\nThe logic is changed a bit, rest everything remains same.\n\n**Note:** the `destinationIndexPath` obtained from `coordinator` in `collectionView(_:performDropWith:)` could be the number of items in collection view if you try to reorder the item to the end of the collection view. In case of reordering, number of items in collection view remain same. So you need to handle that explicitly as it might throw `Array index out of bounds` runtime error.\n\nOh Wait ! I have `destinationIndexPath` , but from where do I get `sourceIndexPath`?\n\nWell, we have an answer for that too.\n\n`[sourceIndexPath](https://developer.apple.com/documentation/uikit/uicollectionviewdropitem/2897392-sourceindexpath)` can be obtained corresponding to each item fetched using `coordinator` . If the item is originated from the same collection view, this property contains the item’s original index path.\n\n!(https://avatars1.githubusercontent.com/u/22985285?s=400&v=4)\n\nIn the above code, a single item is reordered. You can do it for multiple items as per your requirement.\n\n#### Reordering Speed — reorderingCadence\n\nIn case of reordering, when you drag an item over a collection view which accepts a drop, the collection view provides an appropriate visual feedback to the user — shifting/reordering the cells to accomodate a new one.\n\nWe can control the reordering speed for a better user experience using [reorderingCadence](https://developer.apple.com/documentation/uikit/uicollectionview/2897347-reorderingcadence) of type [enum UICollectionViewReorderingCadence](https://developer.apple.com/documentation/uikit/uicollectionviewreorderingcadence) on collection view object.\n\n`reorderingCadence` can have these possible values:\n\n1. `immediate` — Items are reordered into place immediately. (**default value**)\n2. `fast` — Items are reordered quickly, but with a short delay.\n3. `slow` — Items are reordered after a delay.\n\nSet the appropriate value of `reorderingCadence` on your collection view object in `viewDidLoad()`.\n\ncollectionView.reorderingCadence = .fast\n\n#### Drag Preview — UIDragPreviewParameters\n\nWhen an item is lifted, the collection view uses the item’s visible bounds to create the preview by default. In case you want to customize the appearance of the item, you can achieve it through preview parameters.\n\n[UIDragPreviewParameters](https://developer.apple.com/documentation/uikit/uidragpreviewparameters) — A set of parameters for adjusting the appearance of a drag item preview.\n\nThe parameters specify different visual aspects of the preview, including the background color and the visible area of the view associated with the preview.\n\nIn case you don’t want to make any changes to the drag preview, don’t implement this method or return `nil` if you implement it.\n\nTo customize the drag preview, implement `[collectionView(_:dragPreviewParametersForItemAt:)](https://developer.apple.com/documentation/uikit/uicollectionviewdragdelegate/2897459-collectionview)` method of `UICollectionViewDropDelegate` .\n\n!(https://avatars1.githubusercontent.com/u/22985285?s=400&v=4)\n\nThat’s it. That’s all you need to get drop-drop working in collection and table view. Go on..give it a try !!\n\n### Sample Project\n\nYou can download the sample project from [here](https://github.com/pgpt10/DragAndDrop-CollectionView).\n\n!(https://hackernoon.com/hn-images/1*ST2JF7fK3Ao5L82amVt0RA.gif)\n\n### Promotions\n\nDon’t forget to read my other articles:\n\n1. [Everything about Codable in Swift 4](https://hackernoon.com/everything-about-codable-in-swift-4-97d0e18a2999 "https://hackernoon.com/everything-about-codable-in-swift-4-97d0e18a2999")\n2. [Everything you’ve always wanted to know about notifications in iOS](https://medium.freecodecamp.org/ios-10-notifications-inshorts-all-in-one-ad727e03983a)\n3. [Color it with GRADIENTS — iOS](https://hackernoon.com/color-it-with-gradients-ios-a4b374c3c79f)\n4. [All you need to know about Today Extensions (Widget) in iOS 10](https://hackernoon.com/app-extensions-and-today-extensions-widget-in-ios-10-e2d9fd9957a8 "https://hackernoon.com/app-extensions-and-today-extensions-widget-in-ios-10-e2d9fd9957a8")\n5. [UICollectionViewCell selection made easy..!!](https://hackernoon.com/uicollectionviewcell-selection-made-easy-41dae148379d "https://hackernoon.com/uicollectionviewcell-selection-made-easy-41dae148379d")\n\nFeel free to leave comments in case you have any doubts.