On an iPad esspecially, it is often the case that you may have multiple UITableViews on the screen at the one time, unlike on the iPhone. I wanted to have two UITableView that I could drag and drop cells between the two to swap items between a set of all possible choices and a set of selected choices.

Creating DragAndDropTableViewController
The key to this method is recognising that the UILongPressGestureRecognizer is a continuous event that even after it has been fired your receiver will get UIGestureRecognizerStateChanged events that correspond to where your finger is after the long press has been performed. This is important to note since it lets you know where your finger is on the screen after the long press has begun allowing you to detect dragging.

First I added a long press gesture to the UITableViewCell that is to be dragged and dropped.

I added this UILongPressGestureRecognizer into a superclass called DragAndDropTableViewController as the handler itself does not need to be exposed and while it is quite simple it is not the prettiest but it handles some of edge cases that allow this to work and uses delegation to leave the details up to you. Lets have a look and the handler in more detail, first when the long press gesture begins we grab the view that has been pressed (which we know is a cell) and find the NSindexPath for it in our UITableView. We then fire off a method to the delegate to let it know that the dragging has begun, this is where the delegate (in my example) stores the item that the cell represents and creates the draggable representation however, I will get to that soon. The you grab the view from the delegate that will be the draggable representation, now for the key part you have to take the gesture from the cell and pass it over to the draggable representation. This means that the draggable view will continue to receive the touch gestures for the current instance of the recogniser giving the seamless dragging experience. I disable the scrolling of the tableView otherwise the table scrolls as you move your dragged item around so the quick fix was just to disable this.

Now that we have attached the gesture recogniser to the new view if we delete the cell in the draggingGestureDidBegin in the delegate it will not be released and will keep firing so now we can pass on the UIGestureRecognizerStateChanged to the delegate allowing it to reposition the dragging view as the touch moves around the screen.

Finally notify the delegate that the item has been dropped and that the dragging has ended. At this point the delegate should look at the view that the item has been dropped on and take appropriate action. You also have to remember to re-enable the scrolling so the tableView act as normal once dragging ends.

case UIGestureRecognizerStateEnded:{
UIView *draggedView = [self.draggableDelegate dragAndDropTableViewControllerView:self];
if(draggedView==nil)
return;
//this does not seem like the best way to do this yet you really don't want to fire one after the other I don't think
[self.draggableDelegate dragAndDropTableViewController:self draggingGestureDidEnd:gesture];
[self.dropableDelegate dragAndDropTableViewController:self droppedGesture:gesture];
[self.tableView setScrollEnabled:YES];
[self.tableView reloadData];
}

Using DragAndDropTableViewController
As you have seen the DragAndDropTableViewController is relatively simple and you can use it very simply should you want to achieve the dragging and dropping of cells between tables By implementing the DraggableDelegate and DroppableDelegate. First you must implement draggingGestureDidBegin and decide how to handle the dragging of a cell. In the draggingGestureWillBegin I take the cell that has been selected and take a snap shot of it. Note: To grab the snapshot of the CALayer you need to add the QuartzCore framework and include it, I add it to the pre-compiled header (.pch file). Then I construct a view to drag with a UIView and a UIImageView subview which displays the snap shot of the cell.

In the draggingGestureDidBegin I remove the cell from the table to make it look like the cell has been popped out of the table. You have to have a handle to the item that this cell represents so you can add it to the correct view when the user drops the view. The final method here returns the dragged view created in the draggingGestureWillBegin so that this can be used in the DragAndDropTableViewController to attach the gesture that was originally associated with the cell selected.

The final two delegate methods are very straight forward, in draggingGestureDidMove you must remember to update the position of the draggable view when the gesture moves and in draggingGestureDidEnd remove the dragged view when dragging ends.

At the moment if you drop the cell on a view that I haven’t handled for adding items through this method the item is effectively deleted but you could handle this to make the view bounce back the view it came from or use the draggingGestureDidMove to detect the view the item is over to show that it will be deleted similar to the smoke puff for items being pulled from the dock on Mac OS X. I would love to here your feedback to improve this as I think this could be something that is very useful for lots of people here is the code for the DragAndDropTutorial for you to give it a go.