descargar - Deslice completamente UITableViewCell para eliminar UITableView iOS 8
ios 8.0 para iphone 4 (4)
Me gustaría imitar la función de deslizar para eliminar de un UITableViewCell como la aplicación de correo en iOS 8. No me refiero a deslizar para revelar un botón de eliminar. Me refiero a cuando se desliza, se descartan 3 acciones, pero si sigue deslizando hacia la izquierda, se eliminará el correo electrónico.
En iOS 8, UITableView tiene un nuevo método en el que puede proporcionar los datos para mostrar cualquier número de botones:
#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
No veo ninguna API para detectar si sigues deslizando. He grepped para 8_0 en UITableView.h y el método anterior parece ser el único nuevo.
Supongo que uno podría monitorear el desplazamiento de la vista de desplazamiento, o agregar / secuestrar un UIPanGestureRecognizer. Solo quería asegurarme de usar la forma predeterminada, si existe una (y obtener la animación para "gratis")
Con Swift 4.2 y iOS 12, de acuerdo con sus necesidades, puede elegir una de las 3 formas siguientes para crear una acción de barrido final que eliminará el UITableViewCell
seleccionado.
# 1. Usando el UITableViewDataSource
de tableView(_:commit:forRowAt:)
Cuando usa tableView(_:commit:forRowAt:)
con un estilo de editingStyle
de valor UITableViewCell.EditingStyle.delete
, el sistema admite automáticamente el deslizamiento completo para eliminar.
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. Uso de UITableViewDelegate
de tableView(_:editActionsForRowAt:)
y UITableViewRowAction
Para admitir el barrido completo para eliminar con UITableViewRowAction
, debe inicializarlo con un style
que tenga un valor de 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. Uso de UITableViewDelegate
de tableView(_:trailingSwipeActionsConfigurationForRowAt:)
y UISwipeActionsConfiguration
(requiere iOS 11)
UISwipeActionsConfiguration
tiene una propiedad llamada performsFirstActionWithFullSwipe
. performsFirstActionWithFullSwipe
tiene la siguiente declaración:
var performsFirstActionWithFullSwipe: Bool { get set }
Un valor booleano que indica si un barrido completo realiza automáticamente la primera acción. [...] Cuando esta propiedad se establece en
true
, un barrido completo en la fila realiza la primera acción enumerada en la propiedad deactions
. El valor predeterminado de esta propiedad estrue
.
La siguiente implementación de UITableViewController
muestra cómo utilizar UISwipeActionsConfiguration
para administrar el barrido completo para eliminar acciones.
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
}
}
El origen de datos de la vista de tabla tiene que implementar
-tableView:commitEditingStyle:forRowAtIndexPath:
de lo contrario, la funcionalidad de deslizamiento de iOS 8 incorporada no funcionará.
Esto parece contrario a la UITableViewRowAction
ya que un UITableViewRowAction
acepta un bloque. Pero es la única forma en que he podido hacerlo funcionar.
Puede utilizar MGSwipeTableCell . Han implementado esta función para activar la devolución de llamada swipeTableCell: tappedButtonAtIndex: direction: fromExpansion: con tappedButtonAtIndex igual a 0 (para que se ejecute lo que implementó en el primer botón agregado).
agregue el reconocedor ui gustere a cada celda, verifique la cantidad de "swipness", si se encuentra por encima de un umbral específico, haga la eliminación.
algo como:
- (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");
}
}
}