Full swipe UITableViewCell to delete UITableView iOS 8
With Swift 4.2 and iOS 12, according to your needs, you can choose one of the 3 following ways in order to create a trailing swipe action that will delete the selected UITableViewCell
.
#1. Using UITableViewDataSource
's tableView(_:commit:forRowAt:)
When you use tableView(_:commit:forRowAt:)
with an editingStyle
of value UITableViewCell.EditingStyle.delete
, full swipe to delete is automatically supported by the system.
import UIKitclass TableViewController: UITableViewController { var numbers = [Int](0..<10) override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return numbers.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = "\(numbers[indexPath.row])" return cell } override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == UITableViewCell.EditingStyle.delete) { self.numbers.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .fade) } }}
#2. Using UITableViewDelegate
's tableView(_:editActionsForRowAt:)
and UITableViewRowAction
In order to support full swipe to delete with UITableViewRowAction
, you have to initialize it with a style
that has a value of UITableViewRowAction.Style.destructive
.
import UIKitclass TableViewController: UITableViewController { var numbers = [Int](0..<10) override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return numbers.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = "\(numbers[indexPath.row])" return cell } override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { // Intentionally blank in order to be able to use UITableViewRowActions } override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { let deleteHandler: (UITableViewRowAction, IndexPath) -> Void = { _, indexPath in self.numbers.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .fade) } let deleteAction = UITableViewRowAction(style: UITableViewRowAction.Style.destructive, title: "Delete", handler: deleteHandler) // Add more actions here if required return [deleteAction] }}
#3. Using UITableViewDelegate
's tableView(_:trailingSwipeActionsConfigurationForRowAt:)
and UISwipeActionsConfiguration
(requires iOS 11)
UISwipeActionsConfiguration
has a property called performsFirstActionWithFullSwipe
. performsFirstActionWithFullSwipe
has the following declaration:
var performsFirstActionWithFullSwipe: Bool { get set }
A Boolean value indicating whether a full swipe automatically performs the first action. [...] When this property is set to
true
, a full swipe in the row performs the first action listed in theactions
property. The default value of this property istrue
.
The following UITableViewController
implementation show how to use UISwipeActionsConfiguration
in order to manage full swipe to delete actions.
import UIKitclass TableViewController: UITableViewController { var numbers = [Int](0..<10) override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return numbers.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = "\(numbers[indexPath.row])" return cell } override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let handler: UIContextualAction.Handler = { (action: UIContextualAction, view: UIView, completionHandler: ((Bool) -> Void)) in self.numbers.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .fade) completionHandler(true) } let deleteAction = UIContextualAction(style: UIContextualAction.Style.destructive, title: "Delete", handler: handler) // Add more actions here if required let configuration = UISwipeActionsConfiguration(actions: [deleteAction]) configuration.performsFirstActionWithFullSwipe = true return configuration }}
add ui gustere recognizer to each cell, check the amount of "swipness", if its above specific threshold, do the deletion.
somthing like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"identifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]]; } UISwipeGestureRecognizer* swipe_gesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeLeft:)]; [swipe_gesture setDirection:UISwipeGestureRecognizerDirectionLeft]; [cell addGestureRecognizer:swipe_gesture]; return cell; }- (void)swipeLeft:(UIGestureRecognizer *)gestureRecognizer { int threshold = 100; if (sender.state == UIGestureRecognizerStateBegan) { startLocation = [sender locationInView:self.view]; } else if (sender.state == UIGestureRecognizerStateEnded) { CGPoint stopLocation = [sender locationInView:self.view]; CGFloat dx = stopLocation.x - startLocation.x; CGFloat dy = stopLocation.y - startLocation.y; CGFloat distance = sqrt(dx*dx + dy*dy ); if (distance > threshold ) { NSLog(@"DELETE_ROW"); } }}
Your table view's data source has to implement
-tableView:commitEditingStyle:forRowAtIndexPath:
otherwise the built-in iOS 8 swiping functionality will not work.
This seems counterintuitive since a UITableViewRowAction
accepts a block. But it's the only way I've been able to get it to work.