问题
I'd like to mimic the swipe to delete function of a UITableViewCell just like the mail app in iOS 8. I'm not referring to swipe to reveal a delete button. I'm referring to when you swipe, it discoloses 3 actions, but if you keep swiping to the left, the email is deleted.
In iOS 8, UITableView has a new method where you can provide the data to display any number of buttons:
#ifdef __IPHONE_8_0
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewRowAction *viewStackRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Stack" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
SM_LOG_DEBUG(@"View Stack Action");
}];
viewStackRowAction.backgroundColor = [UIColor radiusBlueColor];
UITableViewRowAction *viewUserRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"User" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
SM_LOG_DEBUG(@"View User Action");
}];
viewUserRowAction.backgroundColor = [UIColor radiusLightBlueColor];
UITableViewRowAction *deleteRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Delete" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
SM_LOG_DEBUG(@"Delete");
}];
deleteRowAction.backgroundColor = [UIColor redColor];
return @[deleteRowAction, viewUserRowAction, viewStackRowAction];
}
#endif
I don't see any API to detect if you keep swiping though. I've grepped for 8_0 in UITableView.h and the above method seems to be the only new one.
I suppose one could monitor the scroll view offset, or add/hijack a UIPanGestureRecognizer. I just wanted to make sure to use the default way, if there is one (and get the animation for "free")
回答1:
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 UIKit
class 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 UIKit
class 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 UIKit
class 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
}
}
回答2:
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");
}
}
}
回答3:
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.
回答4:
You can use MGSwipeTableCell. They have implement this feature to fire callback swipeTableCell:tappedButtonAtIndex:direction:fromExpansion: with tappedButtonAtIndex equal to 0 (so it gets executed what you implemented on first added button).
来源:https://stackoverflow.com/questions/26002751/full-swipe-uitableviewcell-to-delete-uitableview-ios-8