在iOS 8中,如何通过完全滑动UITableViewCell来删除UITableView?

18
我想模仿UITableViewCell中iOS 8邮件应用程序中的滑动删除功能。我指的不是滑动以显示删除按钮,而是当您滑动时,它会显示3个操作,但如果继续向左滑动,则会删除电子邮件。
在iOS 8中,UITableView有一个新方法,可以提供要显示任意数量按钮的数据:
#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

我没有看到任何用于检测连续滑动的API。我在UITableView.h中搜索了8_0,上述方法似乎是唯一的新方法。

我想可以监视滚动视图偏移量,或添加/劫持UIPanGestureRecognizer。我只想确保使用默认方式,如果有的话(并获得“免费”的动画效果)。

4个回答

6
使用Swift 4.2和iOS 12,根据您的需求,有以下3种方法可以创建一个拖动滑动操作来删除所选的UITableViewCell

#1. 使用UITableViewDataSourcetableView(_:commit:forRowAt:)

当您在editingStyle值为UITableViewCell.EditingStyle.delete时使用tableView(_:commit:forRowAt:),系统会自动支持完全滑动删除。

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. 使用UITableViewDelegatetableView(_:editActionsForRowAt:)UITableViewRowAction

为了支持使用UITableViewRowAction进行全屏滑动删除,您需要使用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. 使用UITableViewDelegatetableView(_:trailingSwipeActionsConfigurationForRowAt:)UISwipeActionsConfiguration (需要iOS 11) UISwipeActionsConfiguration有一个名为performsFirstActionWithFullSwipe的属性。 performsFirstActionWithFullSwipe的声明如下:
var performsFirstActionWithFullSwipe: Bool { get set }

一个布尔值,指示完整的滑动是否自动执行第一个操作。[...] 当将此属性设置为true时,在行中进行完整的滑动会执行actions属性中列出的第一个操作。此属性的默认值为true

下面的UITableViewController实现展示了如何使用UISwipeActionsConfiguration来管理完整滑动删除操作。

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
    }

}

1
是的,我很高兴看到他们已经添加了这个。 - VaporwareWolf

2

为每个单元格添加UI手势识别器,检查“滑动程度”的数量,如果超过特定的阈值,则进行删除。

类似于:

    - (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");
        }

    }
}

你好。如果你能更具体地解释一下会更好。在 swipeLeft 方法中,你使用了 sender 和 startLocation。它们来自哪里?你在哪里添加这些方法?谢谢。 - Souhaib Guitouni

0
你可以使用MGSwipeTableCell。他们已经实现了这个功能,通过调用swipeTableCell:tappedButtonAtIndex:direction:fromExpansion:回调函数,并将tappedButtonAtIndex设置为0(这样就会执行你在第一个添加的按钮上实现的内容)。

0

你的表视图数据源必须实现

-tableView:commitEditingStyle:forRowAtIndexPath:

否则,内置的iOS 8滑动功能将无法正常工作。
这似乎是违反直觉的,因为UITableViewRowAction接受一个块。但这是我能让它正常工作的唯一方法。

4
这并不能通过完整的滑动来删除表格中的单元格。它只能显示删除按钮,用户仍然需要点击按钮才能删除。 - Jingshao Chen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接