Learn how to move table view cells with a long press gesture!
This is a companion discussion topic for the original entry at http://www.raywenderlich.com/63089/cookbook-moving-table-view-cells-with-a-long-press-gesture
Learn how to move table view cells with a long press gesture!
__block CGPoint center = cell.center;
snapshot.center = center;
snapshot.alpha = 0.0;
[self.tableView addSubview:snapshot];
[UIView animateWithDuration:0.25 animations:^{
center.y = location.y;
snapshot.center = center;
snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);
snapshot.alpha = 0.98;
cell.alpha = 0.0;
} completion:^(BOOL finished) {
cell.hidden = YES;
}];
In the above code i can do these same set of operations without using __block and
^{}. then what is the purpose of using block here.
Sorry, Iām not sure what you mean that it would work without __block
directive. __block
allows updating center
in the animation block; otherwise you get a compilation error: Read-only variable is not assignable.
^{} is also for the animation block, and it captures center
variable. Without __block
, center
is captured by the block as a read-only variable. By using __block
directive, you make mutable inside the animation block.
Swift version(made with 2.2)
var snapShot: UIView?
var sourceIndexPath: NSIndexPath?
func addLongGestureRecognizerForTableView() {
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.handleTableViewLongGesture(_:)) )
tableView.addGestureRecognizer(longGesture)
}
func handleTableViewLongGesture(sender: UILongPressGestureRecognizer) {
let state = sender.state
let location = sender.locationInView(tableView)
guard let indexPath = tableView.indexPathForRowAtPoint(location) else {
return
}
switch state {
case .Began:
sourceIndexPath = indexPath
guard let cell = tableView.cellForRowAtIndexPath(indexPath) else {
return
}
//Take a snapshot of the selected row using helper method.
snapShot = customSnapShotFromView(cell)
// Add the snapshot as subview, centered at cell's center...
var center = CGPoint(x: cell.center.x, y: cell.center.y)
snapShot?.center = center
snapShot?.alpha = 0.0
tableView.addSubview(snapShot!)
UIView.animateWithDuration(0.25, animations: {
// Offset for gesture location.
center.y = location.y
self.snapShot?.center = center
self.snapShot?.transform = CGAffineTransformMakeScale(1.05, 1.05)
self.snapShot?.alpha = 0.98
cell.alpha = 0.0
}, completion: { _ in
cell.hidden = true
})
case .Changed:
guard let snapShot = snapShot else {
return
}
guard let sourceIndexPathTmp = sourceIndexPath else {
return
}
var center = snapShot.center
center.y = location.y
snapShot.center = center
// Is destination valid and is it different from source?
if !indexPath.isEqual(sourceIndexPathTmp) {
//self made exchange method
objects.exchangeObjectAtIndex(indexPath.row, withObjectAtIndex: sourceIndexPathTmp.row)
// ... move the rows.
tableView.moveRowAtIndexPath(sourceIndexPathTmp, toIndexPath: indexPath)
// ... and update source so it is in sync with UI changes.
sourceIndexPath = indexPath
}
default:
guard let sourceIndexPathTmp = sourceIndexPath else {
return
}
guard let cell = tableView.cellForRowAtIndexPath(sourceIndexPathTmp) else {
return
}
cell.hidden = false
cell.alpha = 0.0
UIView.animateWithDuration(0.25, animations: {
self.snapShot?.center = cell.center
self.snapShot?.transform = CGAffineTransformIdentity
self.snapShot?.alpha = 0.0
cell.alpha = 1.0
}, completion: { _ in
self.sourceIndexPath = nil
self.snapShot?.removeFromSuperview()
self.snapShot = nil
})
}
}
func customSnapShotFromView(inputView: UIView) -> UIImageView{
// Make an image from the input view.
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0)
inputView.layer.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let snapshot = UIImageView(image: image)
snapshot.layer.masksToBounds = false
snapshot.layer.cornerRadius = 0.0
snapshot.layer.shadowOffset = CGSize(width: -5.0, height: 0.0)
snapshot.layer.shadowRadius = 5.0
snapshot.layer.shadowOpacity = 0.4
return snapshot
}
report a bug here:
this guard statement can cause the snapshot to freeze if you drag too far to cause the indexPath variable end up with a value of nil.
the solution is to move the statement into each of the Began and Changed case, like so:
This tutorial is more than six months old so questions are no longer supported at the moment for it. We will update it as soon as possible. Thank you! :]