【问题标题】:Full swipe UITableViewCell to delete UITableView iOS 8完全滑动 UITableViewCell 删除 UITableView iOS 8
【发布时间】:2014-11-18 02:40:38
【问题描述】:

我想模仿 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。我只是想确保使用默认方式,如果有的话(并“免费”获得动画)

【问题讨论】:

    标签: ios uitableview ios8 uipangesturerecognizer


    【解决方案1】:

    在 Swift 4.2 和 iOS 12 中,根据您的需要,您可以选择以下三种方式中的一种,以创建将删除所选UITableViewCell 的拖尾滑动操作。 p>


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

    当您将tableView(_:commit:forRowAt:) 与值为UITableViewCell.EditingStyle.deleteeditingStyle 一起使用时,系统会自动支持完全滑动删除。

    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.destructivestyle 对其进行初始化。

    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
        }
    
    }
    

    【讨论】:

    • 是的,我很高兴看到他们添加了这个。
    【解决方案2】:

    您可以使用MGSwipeTableCell。他们已经实现了这个特性来触发回调 swipeTableCell:tappedButtonAtIndex:direction:fromExpansion: 并且 tappedButtonAtIndex 等于 0(所以它会执行你在第一个添加按钮上实现的操作)。

    【讨论】:

      【解决方案3】:

      你的表格视图的数据源来实现

      -tableView:commitEditingStyle:forRowAtIndexPath:
      

      否则内置的 iOS 8 滑动功能将无法使用。

      这似乎违反直觉,因为 UITableViewRowAction 接受一个块。但这是我能够让它工作的唯一方法。

      【讨论】:

      • 这并不能通过完全滑动来删除表格单元格。它可以显示删除按钮,用户仍然需要触摸按钮才能删除。
      【解决方案4】:

      为每个单元格添加ui gustere识别器,检查“swipness”的数量,如果超过特定阈值,则删除。

      类似:

          - (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。他们来自哪里?你在哪里添加这些方法?谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-20
      • 2014-07-28
      • 1970-01-01
      • 2018-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多