UITableViewCell, show delete button on swipe

IosUitableviewCocoa TouchUikit

Ios Problem Overview


How do I get the delete button to show when swiping on a UITableViewCell? The event is never raised and the delete button never appears.

Ios Solutions


Solution 1 - Ios

During startup in (-viewDidLoad or in storyboard) do:

self.tableView.allowsMultipleSelectionDuringEditing = false

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

Solution 2 - Ios

This answer has been updated to 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. The project performs like this:

enter image description here

This project is based on the UITableView example for Swift.

#Add the Code

Create a new project and replace the ViewController.swift code with the following.

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. 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! 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

enter image description here

Add the following method:

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

Custom button actions

enter image description here

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.

Updated for iOS 11

Actions can be placed either leading or trailing the cell using methods added to the UITableViewDelegate API in iOS 11.

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

Solution 3 - Ios

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;

Solution 4 - Ios

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:

- (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. 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:

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.

Solution 5 - Ios

Below UITableViewDataSource will help you for swipe delete

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

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

Solution 6 - Ios

In iOS 8 and Swift 2.0 please try this,

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

Solution 7 - Ios

@Kurbz's answer is awesome, but I want to leave this note and hope this answer can save people some time.

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. You can only use UITableViewCellEditingStyleDelete, which is the default style.

Solution 8 - Ios

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

Solution 9 - Ios

Also, this can be achieved in SWIFT using the method as follows

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

Solution 10 - Ios

Swift 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()
    }
    
}

Solution 11 - Ios

I know is old question, but @Kurbz answer just need this for Xcode 6.3.2 and SDK 8.3

I need add [tableView beginUpdates] and [tableView endUpdates] (thanks to @bay.phillips here)

// 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];
}

Solution 12 - Ios

When you remove a cell of your tableview, you also have to remove your array object at index 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. 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.

For all other is the answer from Kurbz correct.

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.

I hope I have helped you out.

Solution 13 - Ios

- (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];
    }    
}    

Solution 14 - Ios

Swift 4,5

To delete a cell on swipe there are two built in methods of UITableView.Write this method in TableView dataSource extension.

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
}

Solution 15 - Ios

If you're adopting diffable data sources, you'll have to move the delegate callbacks to a UITableViewDiffableDataSource subclass. 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)
            }
        }
    }
}

Solution 16 - Ios

for swift4 code, first enable editing:

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

Solution 17 - Ios

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

Solution 18 - Ios

For Swift, Just write this code

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

For Objective C, Just write this code

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

Solution 19 - Ios

SWIFT 5 : for 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
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTheLearnerView Question on Stackoverflow
Solution 1 - IosKurbzView Answer on Stackoverflow
Solution 2 - IosSuragchView Answer on Stackoverflow
Solution 3 - Iosma11hew28View Answer on Stackoverflow
Solution 4 - IosLeonView Answer on Stackoverflow
Solution 5 - IosiAnkitView Answer on Stackoverflow
Solution 6 - IosMasa S-AiYaView Answer on Stackoverflow
Solution 7 - IosBrianView Answer on Stackoverflow
Solution 8 - IosPratik LadView Answer on Stackoverflow
Solution 9 - IosDrPatienceView Answer on Stackoverflow
Solution 10 - IosMachadoView Answer on Stackoverflow
Solution 11 - IosBetoView Answer on Stackoverflow
Solution 12 - IosRobybyteView Answer on Stackoverflow
Solution 13 - IosRahul K RajanView Answer on Stackoverflow
Solution 14 - IosMALIKK HABIB UR REHMANView Answer on Stackoverflow
Solution 15 - IosAustin ConlonView Answer on Stackoverflow
Solution 16 - IosAbdoelrhmanView Answer on Stackoverflow
Solution 17 - IoslclView Answer on Stackoverflow
Solution 18 - IosKiran JasvaneeView Answer on Stackoverflow
Solution 19 - IosHaseeb JavedView Answer on Stackoverflow