So I have seen a lot of posts about reordering cells that pertain to using "edit mode", but none for the problem I have. (Excuse me if I am wrong).
I am building a ranking app, and looking for a way to use a long gesture recognizer to reorder the cells in my UITableView. Essentially a user will be able to reorder and "Rank" the cells full of strings in a group with their friends.
I would go the standard route of using an "edit" bar button item in the nav bar, but I am using the top right of the nav bar for adding new strings to the tableview already. (The following image depicts what I mean).
So far, I have added `
var lpgr = UILongPressGestureRecognizer(target: self, action: "longPressDetected:")
lpgr.minimumPressDuration = 1.0;
tableView.addGestureRecognizer(lpgr)`
to my viewDidLoad method, and started creating the following function:
func longPressDetected(sender: AnyObject) {
var longPress:UILongPressGestureRecognizer = sender as UILongPressGestureRecognizer
var state:UIGestureRecognizerState = longPress.state
let location:CGPoint = longPress.locationInView(self.tableView) as CGPoint
var indexPath = self.tableView.indexPathForRowAtPoint(location)?
var snapshot:UIView!
var sourceIndexPath:NSIndexPath!
}
All of the resources I have scowered for on the internet end up showing me a HUGE, LONG list of additives to that function in order to get the desired result, but those examples involve core data. It seems to me that there must be a far easier way to simply reorder tableview cells with a long press?
Dave's answer is great. Here is the swift 4 version of this tutorial:
WayPointCell
is your CustomUITableViewCell
and wayPoints
is the dataSource array for the UITableView
First, put this in your viewDidLoad, like Alfi mentionend:
override func viewDidLoad() {
super.viewDidLoad()
let longpress = UILongPressGestureRecognizer(target: self, action: #selector(longPressGestureRecognized(gestureRecognizer:)))
self.tableView.addGestureRecognizer(longpress)
}
Then implement the method:
func longPressGestureRecognized(gestureRecognizer: UIGestureRecognizer) {
let longpress = gestureRecognizer as! UILongPressGestureRecognizer
let state = longpress.state
let locationInView = longpress.location(in: self.tableView)
var indexPath = self.tableView.indexPathForRow(at: locationInView)
switch state {
case .began:
if indexPath != nil {
Path.initialIndexPath = indexPath
let cell = self.tableView.cellForRow(at: indexPath!) as! WayPointCell
My.cellSnapShot = snapshopOfCell(inputView: cell)
var center = cell.center
My.cellSnapShot?.center = center
My.cellSnapShot?.alpha = 0.0
self.tableView.addSubview(My.cellSnapShot!)
UIView.animate(withDuration: 0.25, animations: {
center.y = locationInView.y
My.cellSnapShot?.center = center
My.cellSnapShot?.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)
My.cellSnapShot?.alpha = 0.98
cell.alpha = 0.0
}, completion: { (finished) -> Void in
if finished {
cell.isHidden = true
}
})
}
case .changed:
var center = My.cellSnapShot?.center
center?.y = locationInView.y
My.cellSnapShot?.center = center!
if ((indexPath != nil) && (indexPath != Path.initialIndexPath)) {
self.wayPoints.swapAt((indexPath?.row)!, (Path.initialIndexPath?.row)!)
//swap(&self.wayPoints[(indexPath?.row)!], &self.wayPoints[(Path.initialIndexPath?.row)!])
self.tableView.moveRow(at: Path.initialIndexPath!, to: indexPath!)
Path.initialIndexPath = indexPath
}
default:
let cell = self.tableView.cellForRow(at: Path.initialIndexPath!) as! WayPointCell
cell.isHidden = false
cell.alpha = 0.0
UIView.animate(withDuration: 0.25, animations: {
My.cellSnapShot?.center = cell.center
My.cellSnapShot?.transform = .identity
My.cellSnapShot?.alpha = 0.0
cell.alpha = 1.0
}, completion: { (finished) -> Void in
if finished {
Path.initialIndexPath = nil
My.cellSnapShot?.removeFromSuperview()
My.cellSnapShot = nil
}
})
}
}
func snapshopOfCell(inputView: UIView) -> UIView {
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0.0)
inputView.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
let cellSnapshot : UIView = UIImageView(image: image)
cellSnapshot.layer.masksToBounds = false
cellSnapshot.layer.cornerRadius = 0.0
cellSnapshot.layer.shadowOffset = CGSize(width: -5.0, height: 0.0)
cellSnapshot.layer.shadowRadius = 5.0
cellSnapshot.layer.shadowOpacity = 0.4
return cellSnapshot
}
struct My {
static var cellSnapShot: UIView? = nil
}
struct Path {
static var initialIndexPath: IndexPath? = nil
}
Give this tutorial a shot, you'll likely be up and running within 20 minutes:
Great Swift Drag & Drop tutorial
It's easy. I've only been developing for 3 months and I was able to implement this. I also tried several others and this was the one I could understand.
It's written in Swift and it's practically cut and paste. You add the longPress code to your viewDidLoad and then paste the function into the 'body' of your class. The tutorial will guide you but there's not much more to it.
Quick explanation of the code: This method uses a switch statement to detect whether the longPress just began, changed, or is in default. Different code runs for each case. It takes a snapshot/picture of your long-pressed cell, hides your cell, and moves the snapshot around. When you finished, it unhides your cell and removes the snapshot from the view.
Warning: My one word of caution is that although this drag/drop looks great and works close to perfectly, there does seem to be an issue where it crashes upon dragging the cell below the lowest/bottom cell.
Drag & Drop Crash Problem
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With