Mobile App Development



How to Create Drag and Drop Cells in Swift using an UILongPressGestureRecognizer

January 23, 2015

Dan Fairbanks

By Dan Fairbanks

While working on a recent project for a client, I needed to implement a drag and drop table view for moving cells around. As I did some research, I found a great tutorial on The only problem was that it was in Objective-C and I was writing my project in Swift.

I couldn’t just simply translate the syntax and have it all working properly because of differences between the two. So, I created this tutorial on how to create a drag and drop UITableView in Swift using a UILongPressGestureRecognizer.

I’m going to assume that you know how to make a UITableView and fill it with data. If not,  I have provided a starter project with an UITableViewController filled with some data from an Array. You can download the starter project here.

The first thing you need to do is add a gesture recognizer to the tableView.

In ViewDidLoad() add the following code:

let longpress = UILongPressGestureRecognizer(target: self, action: "longPressGestureRecognized:")

Now, add the longPressGestureRecognized function with the follow code:

func longPressGestureRecognized(gestureRecognizer: UIGestureRecognizer) {

Inside the longPressGestureRecognized() function, start by getting the location of the gesture in the table view and the corresponding tableViewCell.

Add the following code inside the longPressGestureRecognized() function:

let longPress = gestureRecognizer as UILongPressGestureRecognizer
let state = longPress.state
var locationInView = longPress.locationInView(tableView)
var indexPath = tableView.indexPathForRowAtPoint(locationInView)

Next, create a switch statement beginning with UIGestureRecognizerState.Began. Check that the index path is not nil. If not, then take a snapshot of the cell with a forthcoming method, add the snapshot of the cell to the view and hide the cell.

But first, create some variables for the cell snapshot and the initial index path. These variables need to be structs so that we can access their values later in the code. (This is something that wasn’t necessary in Objective-C.) Add the following code to the bottom of the longPressGestureRecognized() function:


struct My {
static var cellSnapshot : UIView? = nil
struct Path {
static var initialIndexPath : NSIndexPath? = nil

Now add this code below that:

switch state {
case UIGestureRecognizerState.Began:
if indexPath != nil {
Path.initialIndexPath = indexPath
let cell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!
My.cellSnapshot  = snapshopOfCell(cell)
var center =
My.cellSnapshot!.center = center
My.cellSnapshot!.alpha = 0.0
UIView.animateWithDuration(0.25, animations: { () -> Void in
center.y = locationInView.y
My.cellSnapshot!.center = center
My.cellSnapshot!.transform = CGAffineTransformMakeScale(1.05, 1.05)
My.cellSnapshot!.alpha = 0.98
cell.alpha = 0.0
}, completion: { (finished) -> Void in
if finished {
cell.hidden = true


To add the snapshot function, enter the following code below the longPressGestureRecognized() function:

func snapshopOfCell(inputView: UIView) -> UIView {
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0.0)
let image = UIGraphicsGetImageFromCurrentImageContext() as UIImage
let cellSnapshot : UIView = UIImageView(image: image)
cellSnapshot.layer.masksToBounds = false
cellSnapshot.layer.cornerRadius = 0.0
cellSnapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0)
cellSnapshot.layer.shadowRadius = 5.0
cellSnapshot.layer.shadowOpacity = 0.4
return cellSnapshot

Next , we need the logic for when the user’s finger moves. If the indexPath is different than the initial indexPath, swap cells and update the data source.

As part of the next piece of the switch statement in longPressGestureRecognized(), add the follow code:


case UIGestureRecognizerState.Changed:
var center = My.cellSnapshot!.center
center.y = locationInView.y
My.cellSnapshot!.center = center
if ((indexPath != nil) && (indexPath != Path.initialIndexPath)) {
swap(&itemsArray[indexPath!.row], &itemsArray[Path.initialIndexPath!.row])
tableView.moveRowAtIndexPath(Path.initialIndexPath!, toIndexPath: indexPath!)
Path.initialIndexPath = indexPath

Finally, clean everything up with some nice animations. For this, use the switch statement default.

Add the following code to the last part of the switch statement in longPressGestureRecognized():


let cell = tableView.cellForRowAtIndexPath(Path.initialIndexPath!) as UITableViewCell!
cell.hidden = false
cell.alpha = 0.0
UIView.animateWithDuration(0.25, animations: { () -> Void in
My.cellSnapshot!.center =
My.cellSnapshot!.transform = CGAffineTransformIdentity
My.cellSnapshot!.alpha = 0.0
cell.alpha = 1.0
}, completion: { (finished) -> Void in
if finished {
Path.initialIndexPath = nil
My.cellSnapshot = nil

That’s it. Test out your code for bugs. If you would like to see my source code for the complete project then go here.


UPDATE: See the comments below for updates to the code above!

Dan Fairbanks

Dan Fairbanks

I am eternally optimistic and believe that the best way to predict the future is to invent it. When I am not programming insanely great iOS apps, you can find me hanging out with my wife and son, reading a book, crossfitting, wakeboarding, or playing in the mountains.

Unless otherwise specified, source code in this post is licensed under a
Creative Commons Attribution 4.0 International license (CC BY 4.0).

You might also like...



Michael Wiggins

How Will the Oracle Java Licensing Changes Affect You?

Earlier this year, Oracle announced that beginning January 1, 2019, it will no longer provide support and updates to Java SE 8. Instead, the support and updates that have been included as part of the Java license will now be available only through a separate subscription support service. As we are now well into the … Continued



Ben Spencer

Dev Terminology 101: Common Programming Languages (and their key frameworks)

Language enables human communication – spoken or written – with words and phrases structured in a conventional way. Just like we need different languages to communicate with one another, we also need different languages to communicate with computers. In an article on Stack Overflow, Matt Sherman writes that at a foundational level, all programming languages … Continued



Xavier Reyes

How to Get Started with the Internet of Things (IoT)

We live in a time when most of the hardware we use is connected to the internet. “Smart devices” started with phones and TVs, but there are now many other internet-connected devices like cars, refrigerators, and home automation systems. The Internet of Things – or IoT – is growing as an industry, with new devices … Continued