简体   繁体   English

UITableViewCell,在滑动时显示删除按钮

[英]UITableViewCell, show delete button on swipe

How do I get the delete button to show when swiping on a UITableViewCell ?如何在UITableViewCell上滑动时显示删除按钮? The event is never raised and the delete button never appears.该事件永远不会引发,删除按钮永远不会出现。

During startup in (-viewDidLoad or in storyboard) do:(-viewDidLoad or in storyboard)启动期间,请执行以下操作:

self.tableView.allowsMultipleSelectionDuringEditing = NO;

Override to support conditional editing of the table view.覆盖以支持表视图的条件编辑。 This only needs to be implemented if you are going to be returning NO for some items.仅当您要为某些项目返回NO时才需要实施。 By default, all items are editable.默认情况下,所有项目都是可编辑的。

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //add code here for when you hit delete
    }    
}

This answer has been updated to Swift 3此答案已更新到 Swift 3

I always think it is nice to have a very simple, self-contained example so that nothing is assumed when I am learning a new task.我一直认为有一个非常简单的、自包含的例子是很好的,这样当我学习一项新任务时什么都不做。 This answer is that for deleting UITableView rows.这个答案是用于删除UITableView行。 The project performs like this:该项目执行如下:

在此处输入图片说明

This project is based on the UITableView example for Swift .该项目基于SwiftUITableView 示例

Add the Code添加代码

Create a new project and replace the ViewController.swift code with the following.创建一个新项目并将 ViewController.swift 代码替换为以下内容。

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    // These strings will be the data for the table view cells
    var animals: [String] = ["Horse", "Cow", "Camel", "Pig", "Sheep", "Goat"]

    let cellReuseIdentifier = "cell"

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // It is possible to do the following three things in the Interface Builder
        // rather than in code if you prefer.
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
        tableView.delegate = self
        tableView.dataSource = self
    }

    // number of rows in table view
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.animals.count
    }

    // create a cell for each table view row
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!

        cell.textLabel?.text = self.animals[indexPath.row]

        return cell
    }

    // method to run when table view cell is tapped
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("You tapped cell number \(indexPath.row).")
    }

    // this method handles row deletion
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

        if editingStyle == .delete {

            // remove the item from the data model
            animals.remove(at: indexPath.row)

            // delete the table view row
            tableView.deleteRows(at: [indexPath], with: .fade)

        } else if editingStyle == .insert {
            // Not used in our example, but if you were adding a new row, this is where you would do it.
        }
    }

}

The single key method in the code above that enables row deletion is the last one.上面代码中启用行删除的单键方法是最后一个。 Here it is again for emphasis:这里再次强调:

// this method handles row deletion
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    if editingStyle == .delete {

        // remove the item from the data model
        animals.remove(at: indexPath.row)

        // delete the table view row
        tableView.deleteRows(at: [indexPath], with: .fade)

    } else if editingStyle == .insert {
        // Not used in our example, but if you were adding a new row, this is where you would do it.
    }
}

Storyboard故事板

Add a UITableView to the View Controller in the storyboard.UITableView添加到故事板中的视图控制器。 Use auto layout to pin the four sides of the table view to the edges of the View Controller.使用自动布局将表格视图的四个边固定到视图控制器的边缘。 Control drag from the table view in the storyboard to the @IBOutlet var tableView: UITableView!控制从 storyboard 中的 table view 拖动到@IBOutlet var tableView: UITableView! line in the code.代码中的行。

Finished完成的

That's all.就这样。 You should be able to run your app now and delete rows by swiping left and tapping "Delete".您现在应该能够运行您的应用程序并通过向左滑动并点击“删除”来删除行。


Variations变化

Change the "Delete" button text更改“删除”按钮文本

在此处输入图片说明

Add the following method:添加以下方法:

func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
    return "Erase"
}

Custom button actions自定义按钮操作

在此处输入图片说明

Add the following method.添加以下方法。

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

    // action one
    let editAction = UITableViewRowAction(style: .default, title: "Edit", handler: { (action, indexPath) in
        print("Edit tapped")
    })
    editAction.backgroundColor = UIColor.blue

    // action two
    let deleteAction = UITableViewRowAction(style: .default, title: "Delete", handler: { (action, indexPath) in
        print("Delete tapped")
    })
    deleteAction.backgroundColor = UIColor.red

    return [editAction, deleteAction]
}

Note that this is only available from iOS 8. See this answer for more details.请注意,这仅适用于 iOS 8。有关更多详细信息,请参阅此答案

Updated for iOS 11针对 iOS 11 更新

Actions can be placed either leading or trailing the cell using methods added to the UITableViewDelegate API in iOS 11.可以使用添加到 iOS 11 中 UITableViewDelegate API 的方法将操作放置在单元格的前导或尾随。

func tableView(_ tableView: UITableView,
                leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
 {
     let editAction = UIContextualAction(style: .normal, title:  "Edit", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
             success(true)
         })
editAction.backgroundColor = .blue

         return UISwipeActionsConfiguration(actions: [editAction])
 }

 func tableView(_ tableView: UITableView,
                trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
 {
     let deleteAction = UIContextualAction(style: .normal, title:  "Delete", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
         success(true)
     })
     deleteAction.backgroundColor = .red

     return UISwipeActionsConfiguration(actions: [deleteAction])
 }

Further reading进一步阅读

This code shows how to implement the delete.这段代码展示了如何实现删除。

#pragma mark - UITableViewDataSource

// Swipe to delete.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [_chats removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }
}

Optionally, in your initialization override, add the line below to show the Edit button item:或者,在您的初始化覆盖中,添加以下行以显示“编辑”按钮项:

self.navigationItem.leftBarButtonItem = self.editButtonItem;

Note: I don't have enough reputation to post a comment in the answer from Kurbz. 注意:我没有足够的声誉在Kurbz的答案中发表评论。

The answer from Kurbz is right. Kurbz的答案是对的。 But for me it never worked. 但对我来说它从来没有奏效。

After some investigation, I realized that swipe-to-delete happens when NOT editing the table view. 经过一些调查,我意识到在不编辑表格视图时会发生滑动到删除。 .

I never seen this explicitly stated as such. 我从未见过如此明确说明。 Unless I'm mistaken, I haven't found any other way to have it work. 除非我弄错了,否则我没有找到任何其他办法让它发挥作用。

When you are editing, the delete and/or reorder control will show up. 编辑时,将显示删除和/或重新排序控件。

I had a problem which I have just managed to solve so I am sharing it as it may help someone.我有一个我刚刚设法解决的问题,所以我分享它,因为它可能对某人有所帮助。

I have a UITableView and added the methods shown to enable swipe to delete:我有一个 UITableView 并添加了显示的方法以启用滑动删除:

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //add code here for when you hit delete
    }    
}

I am working on an update that allows me to put the table into edit mode and enables multiselect.我正在开发一个更新,它允许我将表置于编辑模式并启用多选。 To do that I added the code from Apple's TableMultiSelect sample.为此,我添加了 Apple 的TableMultiSelect示例中的代码。 Once I got that working I found that my swipe the delete function had stopped working.一旦我开始工作,我发现我的滑动删除功能已经停止工作。

It turns out that adding the following line to viewDidLoad was the issue:事实证明,将以下行添加到 viewDidLoad 是问题所在:

self.tableView.allowsMultipleSelectionDuringEditing = YES;

With this line in, the multiselect would work but the swipe to delete wouldn't.有了这一行,多选会起作用,但滑动删除不会。 Without the line it was the other way around.没有这条线,情况正好相反。

The fix:修复:

Add the following method to your viewController:将以下方法添加到您的视图控制器:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    self.tableView.allowsMultipleSelectionDuringEditing = editing; 
    [super setEditing:editing animated:animated];
}

Then in your method that puts the table into editing mode (from a button press for example) you should use:然后在您将表格置于编辑模式的方法中(例如通过按下按钮),您应该使用:

[self setEditing:YES animated:YES];

instead of:代替:

[self.tableView setEditing:YES animated:YES];

This means that multiselect is only enabled when the table is in editing mode.这意味着只有在表格处于编辑模式时才启用多选。

Below UITableViewDataSource will help you for swipe delete下面的 UITableViewDataSource 将帮助您进行滑动删除

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [arrYears removeObjectAtIndex:indexPath.row];
        [tableView reloadData];
    }
}

arrYears is a NSMutableArray and then reload the tableView arrYears是一个 NSMutableArray 然后重新加载 tableView

Swift迅速

 func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
            return true
        }

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == UITableViewCellEditingStyleDelete {
        arrYears.removeObjectAtIndex(indexPath.row)
        tableView.reloadData()
    }
}

In iOS 8 and Swift 2.0 please try this,在 iOS 8 和 Swift 2.0 请试试这个,

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
   // let the controller to know that able to edit tableView's row 
   return true
}

override func tableView(tableView: UITableView, commitEdittingStyle editingStyle UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)  {
   // if you want to apply with iOS 8 or earlier version you must add this function too. (just left in blank code)
}

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]?  {
   // add the action button you want to show when swiping on tableView's cell , in this case add the delete button.
   let deleteAction = UITableViewRowAction(style: .Default, title: "Delete", handler: { (action , indexPath) -> Void in

   // Your delete code here.....
   .........
   .........
   })

   // You can set its properties like normal button
   deleteAction.backgroundColor = UIColor.redColor()

   return [deleteAction]
}

@Kurbz's answer is awesome, but I want to leave this note and hope this answer can save people some time. @Kurbz 的回答很棒,但我想留下这个笔记,希望这个回答可以为人们节省一些时间。

I occasionally had these lines in my controller, and they made the swiping feature not working.我的控制器中偶尔会有这些线条,它们使滑动功能不起作用。

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleNone; 
}

If you use UITableViewCellEditingStyleInsert or UITableViewCellEditingStyleNone as the editing style, then the swiping feature doesn't work.如果您使用UITableViewCellEditingStyleInsertUITableViewCellEditingStyleNone作为编辑样式,则滑动功能不起作用。 You can only use UITableViewCellEditingStyleDelete , which is the default style.您只能使用UITableViewCellEditingStyleDelete ,这是默认样式。

Swift 4斯威夫特 4

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let delete = UITableViewRowAction(style: .destructive, title: "delete") { (action, indexPath) in
        // delete item at indexPath
    tableView.deleteRows(at: [indexPath], with: .fade)

    }
    return [delete]
}

Also, this can be achieved in SWIFT using the method as follows此外,这可以使用以下方法在 SWIFT 中实现

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if (editingStyle == UITableViewCellEditingStyle.Delete){
        testArray.removeAtIndex(indexPath.row)
        goalsTableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
    }
}

Swift 3斯威夫特 3

All you have to do is enable these two functions:您所要做的就是启用这两个功能:

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {

    return true

}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

    if editingStyle == UITableViewCellEditingStyle.delete {
        tableView.reloadData()
    }

}

I know is old question, but @Kurbz answer just need this for Xcode 6.3.2 and SDK 8.3我知道这是个老问题,但@Kurbz 的回答只需要 Xcode 6.3.2 和 SDK 8.3

I need add [tableView beginUpdates] and [tableView endUpdates] (thanks to @bay.phillips here )我需要添加[tableView beginUpdates][tableView endUpdates] (感谢 @bay.phillips 在这里

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    // Open "Transaction"
    [tableView beginUpdates];

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // your code goes here
        //add code here for when you hit delete
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
     }

    // Close "Transaction"
    [tableView endUpdates];
}

When you remove a cell of your tableview, you also have to remove your array object at index x.当您删除 tableview 的单元格时,您还必须删除索引 x 处的数组对象。

I think you can remove it by using a swipe gesture.我认为您可以使用滑动手势将其删除。 The table view will call the Delegate:表视图将调用委托:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //add code here for when you hit delete
        [dataSourceArray removeObjectAtIndex:indexPath.row];
    }    
}

After removing the object.取出物体后。 You have to reload the tableview use.您必须重新加载 tableview 使用。 Add the following line in your code:在您的代码中添加以下行:

[tableView reloadData];

after that, you have deleted the row successfully.之后,您已成功删除该行。 And when you reload the view or adding data to the DataSource the object will not be there anymore.当您重新加载视图或向 DataSource 添加数据时,该对象将不再存在。

For all other is the answer from Kurbz correct.对于所有其他人,Kurbz 的答案是正确的。

I only wanted to remind you that the delegate function won't be enough if you want to remove the object from the DataSource array.我只想提醒您,如果您想从 DataSource 数组中删除对象,那么委托函数是不够的。

I hope I have helped you out.我希望我帮助了你。

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        //add code here for when you hit delete
        [dataSourceArray removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }    
}    

for swift4 code, first enable editing:对于 swift4 代码,首先启用编辑:

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    return true
}

then you add delete action to the edit delegate:然后向编辑委托添加删除操作:

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
    let action = UITableViewRowAction(style: .destructive, title: "Delete") { (_, index) in
        // delete model object at the index
        self.models[index.row]
        // then delete the cell
        tableView.beginUpdates()
        tableView.deleteRows(at: [index], with: .automatic)
        tableView.endUpdates()

    }
    return [action]
}

If you're adopting diffable data sources, you'll have to move the delegate callbacks to a UITableViewDiffableDataSource subclass.如果您采用 diffable 数据源,则必须将委托回调移动到UITableViewDiffableDataSource子类。 For example:例如:

class DataSource: UITableViewDiffableDataSource<SectionType, ItemType> {

    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            if let identifierToDelete = itemIdentifier(for: indexPath) {
                var snapshot = self.snapshot()
                snapshot.deleteItems([identifierToDelete])
                apply(snapshot)
            }
        }
    }
}

Swift 2.2 :斯威夫特 2.2:

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true
}

override func tableView(tableView: UITableView,
    editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
    let delete = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "DELETE"){(UITableViewRowAction,NSIndexPath) -> Void in

    print("Your action when user pressed delete")
}
let edit = UITableViewRowAction(style: UITableViewRowActionStyle.Normal, title: "EDIT"){(UITableViewRowAction,NSIndexPath) -> Void in

    print("Your action when user pressed edit")
}
    return [delete, block]
}

For Swift, Just write this code对于 Swift,只需编写此代码

func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            print("Delete Hit")
        }
}

For Objective C, Just write this code对于目标 C,只需编写此代码

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
       if (editingStyle == UITableViewCellEditingStyleDelete) {           
            NSLog(@"index: %@",indexPath.row);
           }
}

Swift 4,5斯威夫特 4,5

To delete a cell on swipe there are two built in methods of UITableView.Write this method in TableView dataSource extension.要在滑动时删除单元格,有两个内置的 UITableView 方法。在 TableView 数据源扩展中编写此方法。

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
  let delete = deleteProperty(at: indexPath)
  return UISwipeActionsConfiguration(actions: [delete])
}

// Declare this method in UIViewController Main and modify according to your need

func deleteProperty(at indexpath: IndexPath) -> UIContextualAction {
  let action = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completon) in
    self.yourArray.remove(at: indexpath) // Removing from array at selected index

    completon(true)
    action.backgroundColor = .red //cell background color
  }
  return action
}

SWIFT 5 : for iOS 13+ SWIFT 5:适用于 iOS 13+

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
  }
    
    
 func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let deleteAction = UIContextualAction(style: .destructive, title: "Delete") {  (contextualAction, view, boolValue) in
            //Code I want to do here
        }
        
        let editAction = UIContextualAction(style: .destructive, title: "Edit") {  (contextualAction, view, boolValue) in
            //Code I want to do here
        }
        
        let swipeActions = UISwipeActionsConfiguration(actions: [deleteAction, editAction])
        
        return swipeActions
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM