Drag and Drop Table View cell in IOS 11 & swift 4

Drag and Drop Table View cell in IOS 11 & swift 4

In IOS 11, UITableView added the some specialized API for drag and drop the tableView row from one tableView to other tableView. For Drag-Drop we need to implement delegates, UITableViewDragDelegate and UITableViewDropDelegate. UITableView and UICollectionView both have the drag and drop API (Protocols). For UICollectionView You can follow this tutorial.

These Delegates are completly independent, we can use any one delegate for drag and drop according to requirment. And both for Drag-Drop.

NOTE:- please note that Drag-Drop supported in both iPhone and iPad, On iPad use Drag-Drop between different apps, same app, and same screen, But in iPhone use Drag-Drop only on similar screen.

 

First create the base project

Create the base project with two tableView on same screen by the use of CollectionViewDataSource and CollectionViewDelegate methods. You can download the base project from here.

For Drag the table view Cell (UICollectionViewDragDelegate)

Now we start the Drag and drop Delegate for move the tableView row from on FirstTableView to SecondTableView. For get the call back of UITableViewDragDelegate we need to set .dragDelegate in viewDidLoad() method.


1
2
3
4
<span class="hljs-keyword">override</span> <span class="hljs-func"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidLoad</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.viewDidLoad()
        <span class="hljs-keyword">self</span>.topTableView.dragDelegate = <span class="hljs-keyword">self</span>
    }

For enabling the drag intraction we need to set the dragInteractionEnabled property of your table view. Enable this property in viewDidLoad method. The default value of this property is true on iPad and false on iPhone.


1
     <span class="hljs-keyword">self</span>.topTableView.dragInteractionEnabled = <span class="hljs-literal">true</span>

In UITableViewDragDelegate have only one required method itemsForBeginning for support the drag item.

tableView(_:itemsForBeginning:at:) -> Provide items to begin a drag associated with a given indexPath. If an empty array is returned a drag session will not begin.

  • NSItemProvider
  • UIDragItem

NSItemProvider -> By the use of this class you can create the object of your data or file for conveying data or a file between processes during drag and drop.

UIDragItem -> A representation of an underlying data item being dragged from one location to another.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">ViewController</span>: <span class="hljs-title">UITableViewDragDelegate</span> </span>{
    <span class="hljs-func"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath)</span></span> -&gt; [<span class="hljs-type">UIDragItem</span>] {
        <span class="hljs-keyword">let</span> dragItem = <span class="hljs-keyword">self</span>.dragItem(forPhotoAt: indexPath)
        <span class="hljs-keyword">return</span> [dragItem]
    }
    <span class="hljs-comment">/// Helper method</span>
    <span class="hljs-keyword">private</span> <span class="hljs-func"><span class="hljs-keyword">func</span> <span class="hljs-title">dragItem</span><span class="hljs-params">(forPhotoAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UIDragItem</span> {
        <span class="hljs-keyword">let</span> imageName = <span class="hljs-keyword">self</span>.arrayFirst[indexPath.row]
        <span class="hljs-keyword">let</span> data = arrayFisrtProfileData[indexPath.row]
        <span class="hljs-keyword">let</span> string = data.profileImageName
        <span class="hljs-keyword">let</span> itemProvider = <span class="hljs-type">NSItemProvider</span>(object: string <span class="hljs-keyword">as</span> <span class="hljs-type">NSItemProviderWriting</span>)
        <span class="hljs-keyword">let</span> dragItem = <span class="hljs-type">UIDragItem</span>(itemProvider: itemProvider)
        dragItem.localObject = imageName
        <span class="hljs-keyword">return</span> dragItem
    }
}
  1. Create one or more NSItemProvider objects. Use the item providers to represent the data for your table’s rows.
  2. Wrap each item provider object in a UIDragItem object.
  3. Consider assigning a value to the localObject property of each drag item. This step is optional but makes it faster to drag and drop content within the same app.
  4. Return the drag items from your method.

tableView(_:itemsForAddingTo:at:point:) -> This methods is used for adding the item to an active drag session. When drag session is active and user want to add more rows that time table calls this methods. we are getting the point where we can touch for adding the item.
(Or we can say that for selecting multiple items we use this method)

tableView(_:dragPreviewParametersForRowAt:) -> This methods is used when we need to drag only specific location of item at the time of drag.


1
2
3
4
5
6
7
8
9
10
 <span class="hljs-func"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, dragPreviewParametersForRowAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UIDragPreviewParameters</span>? {
        <span class="hljs-keyword">return</span> previewParameters(forItemAt:indexPath)
    }
    <span class="hljs-comment">/// Helper method</span>
    <span class="hljs-keyword">private</span> <span class="hljs-func"><span class="hljs-keyword">func</span> <span class="hljs-title">previewParameters</span><span class="hljs-params">(forItemAt indexPath:IndexPath)</span></span> -&gt; <span class="hljs-type">UIDragPreviewParameters</span>?     {
        <span class="hljs-keyword">let</span> cell = <span class="hljs-keyword">self</span>.topTableView.cellForRow(at: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">TopTableViewCell</span>
        <span class="hljs-keyword">let</span> previewParameters = <span class="hljs-type">UIDragPreviewParameters</span>()
        previewParameters.visiblePath = <span class="hljs-type">UIBezierPath</span>(rect: cell.imageViewProfile.frame)
        <span class="hljs-keyword">return</span> previewParameters
    }

For Drop the table view Cell (UICollectionViewDropDelegate)

First we set the dropDelegate for getting the call back of UICollectionViewDropDelegate methods. we set this property in viewDidLoad() method.


1
    <span class="hljs-keyword">self</span>.bottomTableView.dropDelegate = <span class="hljs-keyword">self</span>

Same as dragDelgate, drop delegate also have one required method performDropWith for support the drop item.

tableView(_:performDropWith:) Use this method to integrate the dropped content into your table view. We getting the destinationIndePath and We retrieve the UIDragItem objects associated with the drag operation. By the use of these object we update the tableView Data source and table View itself.
We can insert placeholder rows for any data that you must load asynchronously.(We discuss this property in future blog)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">ViewController</span>: <span class="hljs-title">UITableViewDropDelegate</span> </span>{
    <span class="hljs-func"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator)</span></span> {
        <span class="hljs-keyword">let</span> destinationIndexPath: <span class="hljs-type">IndexPath</span>
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> indexPath = coordinator.destinationIndexPath {
            destinationIndexPath = indexPath
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">let</span> section = tableView.numberOfSections - <span class="hljs-number">1</span>
            <span class="hljs-keyword">let</span> row = tableView.numberOfRows(inSection: section)
            destinationIndexPath = <span class="hljs-type">IndexPath</span>(row: row, section: section)
        }
        coordinator.session.loadObjects(ofClass: <span class="hljs-type">NSString</span>.<span class="hljs-keyword">self</span>) { items <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> string = items <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>] <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }
            <span class="hljs-keyword">var</span> indexPaths = [<span class="hljs-type">IndexPath</span>]()
            <span class="hljs-keyword">for</span> (index, value) <span class="hljs-keyword">in</span> string.enumerated() {
                <span class="hljs-keyword">let</span> indexPath = <span class="hljs-type">IndexPath</span>(row: destinationIndexPath.row + index, section: destinationIndexPath.section)
                <span class="hljs-keyword">self</span>.arraySecond.insert(value, at: indexPath.row)
                indexPaths.append(indexPath)
            }
            tableView.insertRows(at: indexPaths, with: .automatic)
        }
    }
}

Other optional DropDelegate

DropDelegate also have other methods for handle the drop in tableView. But these methods are optional.
tableView(_:canHandle:) -> This methods is used for handle the drop session. Asks your delegate whether it can accept the specified type of data.


1
2
3
 <span class="hljs-func"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, canHandle session: UIDropSession)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-keyword">return</span> session.canLoadObjects(ofClass: <span class="hljs-type">NSString</span>.<span class="hljs-keyword">self</span>)
    }

UITableViewDropProposal

DropDelagte have the optional method UITableViewDropProposal for handle the drop in table view. Drop proposal have the property for handle the drop when we lift the finger over the item and drop that item.
DropProposal have the operation enum, that determine how we resolved the drag and drop activity when the user drops a drag item. Means we need to drop that that item or not, and that item is compatible for tableView or not.

1
cancel

 This case is used when dont need to transfer the data or should be transferred, that time we cancel the drag.

1
forbidden

 although a move or copy operation is typically legitimate in this scenario, the drop activity is not allowed.

1
copy

 data represented by the drag items should be copied to the destination view.

1
move

 data represented by the drag items should be moved, not copied.

An example methods for UICollectionViewDropProposal


1
2
3
4
5
6
7
<span class="hljs-func"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?)</span></span> -&gt; <span class="hljs-type">UICollectionViewDropProposal</span> {
        <span class="hljs-keyword">if</span> session.localDragSession != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-type">UICollectionViewDropProposal</span>(operation: .move, intent: .insertAtDestinationIndexPath)
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-type">UICollectionViewDropProposal</span>(operation: .copy, intent: .insertAtDestinationIndexPath)
        }
    }




You can download complete project from here.

 

Related Post

First Java Program First Java Program NOTE: You need to have java installed on your system. Step 1: Open a text editor, like Notepad on windows and TextEdit on Mac. W...
How to use Flutter most usable Widgets | Flutter t... We need some basic widgets for creating our first flutter app. Widgets describe what their view should look like given their current configuration and...
Decision Control Statement C has three major decision making instructions— the if statement, the if-else statement, and the switch statement. The if Statement It is used to ex...
Drag and Drop Collection View cell in IOS 11 &... Drag and Drop Collection View cell in IOS 11 & swift 4 In this tutorial we are explain how to drag and drop collection view cell in two collectio...
Switch Case Statement Switch Case Statement The switch statement is a multi-way branch statement. It provides an easy way to dispatch execution to different parts of c...
Java Operators Java Operators An operator is used to perform an operation over one or more operands. It is a character that represents an action, for example * is a...

Leave a Reply

Your email address will not be published. Required fields are marked *