Adding swipe button in table view in swift - ios
I have a simple table view showing a list of tasks. I want to show two buttons when user swipes on a cell. A delete button to delete the cell and Completed button to store the task in completed array. I am able to implement the delete button but no idea of showing a second button in the table cell. here is the code.
import UIKit
var taskArray = [String]()
var datesArray = [String]()
class ViewController: UIViewController, UITableViewDataSource
{
#IBOutlet weak var taskTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return taskArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "taskCell", for: indexPath)
cell.textLabel?.text = "\(indexPath.row + 1). \(taskArray[indexPath.row])"
cell.detailTextLabel?.text = datesArray[indexPath.row]
return cell
}
override func viewDidLoad()
{
super.viewDidLoad()
taskTableView.dataSource = self
let userDefaults = UserDefaults.standard
if let task = userDefaults.stringArray(forKey: "tasks") , let date = userDefaults.stringArray(forKey: "dates")
{
taskArray = task
datesArray = date
}
print(taskArray)
print(datesArray)
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
taskTableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// 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
taskArray.remove(at: indexPath.row)
datesArray.remove(at: indexPath.row)
// delete the table view row
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
//function to come back from close button
#IBAction func close(segue: UIStoryboardSegue)
{
}
}
Swift 4.0
You can write below method of tableView to define custom swipe action.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .default, title: "Delete") { (action, indexPath) in
}
delete.backgroundColor = UIColor.red
let complete = UITableViewRowAction(style: .default, title: "Completed") { (action, indexPath) in
// Do you complete operation
}
complete.backgroundColor = UIColor.blue
return [delete, complete]
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let more = UITableViewRowAction(style: .normal, title: "More") { action, index in
//self.isEditing = false
print("more button tapped")
}
more.backgroundColor = UIColor.lightGray
let favorite = UITableViewRowAction(style: .normal, title: "Favorite") { action, index in
//self.isEditing = false
print("favorite button tapped")
}
favorite.backgroundColor = UIColor.orange
let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
//self.isEditing = false
print("share button tapped")
}
share.backgroundColor = UIColor.blue
return [share, favorite, more]
}
First make this function return true
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
{
return true
}
it makes your cell editable , apple provides default deleting and editing options that you can use as like this :
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if(editingStyle == .delete)
{
myArray.remove(at: indexPath.item)
table.deleteRows(at: [indexPath], with: .automatic)
table.reloadData()
}
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
if(studentUser as? String == "Admin")
{
return .delete
}
else
{
return .none
}
}
or you can define your custom ones :
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
{
let del = UITableViewRowAction(style: .normal, title: "Delete")
{
(action, index) in
let alert = FCAlertView()
alert.makeAlertTypeCaution()
alert.cornerRadius = 10
alert.delegate = self
alert.animateAlertInFromBottom = true
alert.animateAlertOutToTop = true
alert.bounceAnimations = true
alert.blurBackground = true
alert.dismissOnOutsideTouch = true
alert.showAlert(inView: self,
withTitle: "Title you want ",
withSubtitle: "Subtitle Comes here",
withCustomImage: nil,
withDoneButtonTitle:"OK" ,
andButtons:["Cancel"])
}
let edit = UITableViewRowAction(style: .default, title: "Edit")
{
(action, index) in
self.view.makeToast("Editing Coming soon...")
}
del.backgroundColor = AppColor.myNewRedColor
edit.backgroundColor = .lightGray
return [edit,del]
}
Swift 4.0
Add Delegate & DataSource
tableView.delegate = self
tableView.dataSource = self
Add DataSource func "canEditRowAt indexPath"
//MARK: - UITableViewDataSource
public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
Add Delegate func "editActionsForRowAt indexPath"
//MARK: - UITableViewDelegate
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let editAction = UITableViewRowAction(style: .default, title: "Edit", handler: { (action, indexPath) in
//Action edit
print("Action Edit...")
})
editAction.backgroundColor = UIColor.gray //Set button color
let deleteAction = UITableViewRowAction(style: .default, title: "Delete", handler: { (action, indexPath) in
//Action delete
print("Action Delete...")
})
return [deleteAction, editAction]
}
I hope this helps.
As par your Requirement i have . created Demo for you.
Here is the Output,
When you press Delete element will be removed from Array and when you press Add Button element will be added to new Array.
Here is the link of Demo,
Tableview Demo with Swipable Add and Delete
Step 1:- Connect your Tableview datasource and delegate in Storyboard.
Step 2:- Write DataSource Methods of TableView.
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Preloaded Data"
} else {
return "Added Data to New Array"
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return arrPrelodedData.count
} else {
return arrAddNewData.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "SwipeToDelete", for: indexPath) as? SwipeToDelete else {return UITableViewCell()}
if indexPath.section == 0{
cell.lblCellContent.text = arrPrelodedData[indexPath.row] }
else {
cell.lblCellContent.text = arrAddNewData[indexPath.row]
}
return cell
}
//With this we can edit UITableview ex. Swipe to Delete
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
if indexPath.section == 0 {
return true } else {
return false
}
}
//Select tableview Editing Style (insert and Delete)-> if custom icon than set None
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.none
}
//Delete Action 1) Create delete Action 2) Remove data with Indexpath 3) fetch data from coredata 4) delete tableview row 4) set delete button background color 5) return deleteAction in arry wether it is single
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
//Destructive Because we want to delete(destroy) the data from tableview
let deleteAction = UITableViewRowAction(style: .destructive, title: "DELETE") { (rowAction, indexpath) in
self.arrPrelodedData.remove(at: indexPath.row)
tableView.deleteRows(at: [indexpath], with: .automatic)
}
let addAction = UITableViewRowAction(style: .normal, title: "ADD 1") { (rowAction, indexpath) in
self.arrAddNewData.append(self.arrPrelodedData[indexPath.row])
tableView.reloadSections(NSIndexSet(index: 1) as IndexSet, with: .none)
// tableView.reloadRows(at: [indexPath], with: .automatic)
}
deleteAction.backgroundColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
addAction.backgroundColor = #colorLiteral(red: 0.9176470588, green: 0.662745098, blue: 0.2666666667, alpha: 1)
return [deleteAction,addAction]
}
}
I hope this answer will helpful for you.
Related
SwipeCellKit: Why removing an item from list, doesn't update the UITableview?
When I remove an item from list with SwipeTableViewCell, the tableview doesn't get updated. The swiping works, I can also tap on the delete button behind the cell, but once tapped on it, it only hides the delete button but tableview is not updated. This is how my code look like: func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return carList.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell_id", for: indexPath) as! CarCell (cell as SwipeTableViewCell).delegate = self let car = carList[indexPath.row] cell.configure(with: car) return cell } func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? { guard orientation == .right else { return nil } let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in self.carList.remove(at: indexPath.row) } deleteAction.hidesWhenSelected = true return [deleteAction] } It works when I call reloadData of the tableview, but it's not the correct way I guess. The following snippet of code works: func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? { guard orientation == .right else { return nil } let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in self.carList.remove(at: indexPath.row) self.tableView.reloadData() // <-- this works! But without animation } deleteAction.hidesWhenSelected = true return [deleteAction] }
You have to add the code to update the view but instead of reloading the entire table view just delete the row let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in self.carList.remove(at: indexPath.row) self.tableView.deleteRows(at: [indexPath], with: .fade) }
didSelectRowAt is not being called for my table view
I want to make the transition from the UITableView cell to the view controller. My didSelectRowAt isn't working. Here is code: import UIKit class ViewController: UIViewController, UITableViewDelegate { #IBOutlet weak var tableView: UITableView! var goals = [String]() #IBAction func onAddTapped() { let alert = UIAlertController(title: "Add Goal", message: nil, preferredStyle: .alert) alert.addTextField { (dessertTF) in dessertTF.placeholder = "Enter Goal" } let action = UIAlertAction(title: "Add", style: .default) { (_) in guard let goal = alert.textFields?.first?.text else { return } print(goal) self.add(goal) } alert.addAction(action) present(alert, animated: true) } func add(_ goal: String) { let index = 0 goals.insert(goal, at: index) let indexPath = IndexPath(row: index, section: 0) tableView.insertRows(at: [indexPath], with: .left) } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) performSegue(withIdentifier: "segue", sender: self) } } extension ViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return goals.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() let dessert = goals[indexPath.row] cell.textLabel?.text = goals return cell } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { guard editingStyle == .delete else { return } desserts.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .automatic) } }
The problem is that you aren't creating your cells correctly. Inside of your cellForRow function change let cell = UITableViewCell() to this: let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) Make sure that in your storyboard file, that you set the cell identifier to "Cell"
UITableView swipe-to-close in iOS 11
I have some trouble with UITableView swipe-to-close gesture to close actions in a cell. When I open cell actions it works fine, but when I'm trying to close it, it will close only after several trying. I've tested it in a clean project and noticed that it is iOS 11 behaviour because in the previous iOS version these actions are closing by any touch outside action buttons zone. How can I do the same behaviour? Video: https://www.youtube.com/watch?v=rKrk7q0HkeY Code. Just for a case class ViewController: UIViewController { let tableView = UITableView(frame: .zero, style: .plain) var data = (0...3) .map { _ in return (0...5).map { _ in return false } } override func loadView() { super.loadView() view = tableView } override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self tableView.delegate = self } } extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return data[section].count } func numberOfSections(in tableView: UITableView) -> Int { return data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell.init(style: .default, reuseIdentifier: "cell") let isSelected = data[indexPath.section][indexPath.row] cell.textLabel?.text = "Section: \(indexPath.section) \nRow: \(indexPath.row)" cell.textLabel?.numberOfLines = 0 cell.accessoryType = isSelected ? .checkmark : .none return cell } #available(iOS 11.0, *) func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let action = UIContextualAction(style: .normal, title: "Toggle 2") { [weak self] (action, view, handler) in guard let data = self?.data else { return } let isSelected = data[indexPath.section][indexPath.row] self?.data[indexPath.section][indexPath.row] = !isSelected self?.tableView.reloadRows(at: [indexPath], with: .fade) handler(true) } action.backgroundColor = .blue let configuration = UISwipeActionsConfiguration(actions: indexPath.section == 0 ? [action] : []) configuration.performsFirstActionWithFullSwipe = true return configuration } } extension ViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { let action = UITableViewRowAction(style: .default, title: "Toggle") { [weak self] (action, indexPath) in guard let data = self?.data else { return } let isSelected = data[indexPath.section][indexPath.row] self?.data[indexPath.section][indexPath.row] = !isSelected self?.tableView.reloadRows(at: [indexPath], with: .fade) } return [action] } }
I've found the solution. Swipe-to-close works well in iOS 11 if you add leading actions. #available(iOS 11.0, *) func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let action = UIContextualAction(style: .normal, title: "Toggle 2") { [weak self] (action, view, handler) in guard let data = self?.data else { return } let isSelected = data[indexPath.section][indexPath.row] self?.data[indexPath.section][indexPath.row] = !isSelected self?.tableView.reloadRows(at: [indexPath], with: .fade) handler(true) } action.backgroundColor = .blue let configuration = UISwipeActionsConfiguration(actions: indexPath.section == 0 ? [action] : []) configuration.performsFirstActionWithFullSwipe = true return configuration } I've updated question source if someone interested in full code
Expanded and Swipe-able cell in TableView
I have TableView, where users can click and expand each cell (UI: click). This is the code for that (also I created .xib file to layout this cell): class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating { var selectedIndex: IndexPath? var isExpended = false func didExpandCell() { self.isExpended = !isExpended self.tableView.reloadRows(at: [selectedIndex!], with: .automatic) } #IBOutlet weak var tableView: UITableView! ... func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "wordCell", for: indexPath) as! CellController if searchController.isActive { cell.word.text = filtered[indexPath.row].word cell.translation.text = filtered[indexPath.row].translation cell.date.text = filtered[indexPath.row].fullDate cell.exOne.text = filtered[indexPath.row].exOne cell.exTwo.text = filtered[indexPath.row].exTwo } else { cell.word.text = words[indexPath.row].word cell.translation.text = words[indexPath.row].translation cell.date.text = words[indexPath.row].fullDate cell.exOne.text = words[indexPath.row].exOne cell.exTwo.text = words[indexPath.row].exTwo } return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { self.selectedIndex = indexPath self.didExpandCell() } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if isExpended && self.selectedIndex == indexPath { return 180 } return 70 } } Also, all Cells are swipe-able. This is the code: func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? { let edit = UITableViewRowAction(style: .normal, title: "Edit") { action, index in print("Edit") } edit.backgroundColor = .blue let delete = UITableViewRowAction(style: .normal, title: "Delete") { action, index in print("Delete") } delete.backgroundColor = .red return [delete, edit] } func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } The problem: When I swipe Cell, it always expends in a half, this is my UI after swiping: click. Is it possible not to expand Cell if I swipe them?
Excuse me, but the problem was that I haven't set constraints for expanded version of the cell. That's why this labels were moving with swipe menu. Now it works. Thank you for all your replies!
Add swipe to delete UITableViewCell
I am making a CheckList application with a UITableView. I was wondering how to add a swipe to delete a UITableViewCell. This is my ViewController.swift: import UIKit class ViewController: UIViewController, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource { var tableView: UITableView! var textField: UITextField! var tableViewData:Array<String> = [] // Define Colors let lightColor: UIColor = UIColor(red: 0.996, green: 0.467, blue: 0.224, alpha: 1) let medColor: UIColor = UIColor(red: 0.973, green: 0.388, blue: 0.173, alpha: 1) let darkColor: UIColor = UIColor(red: 0.800, green: 0.263, blue: 0.106, alpha: 1) let greenColor: UIColor = UIColor(red: 0.251, green: 0.831, blue: 0.494, alpha: 1) init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) // Custom initialization } override func viewDidLoad() { super.viewDidLoad() //Set up table view self.tableView = UITableView(frame: CGRectMake(0, 100, self.view.bounds.size.width, self.view.bounds.size.height-100), style: UITableViewStyle.Plain) self.tableView.registerClass(MyTableViewCell.self, forCellReuseIdentifier: "myCell") self.tableView.backgroundColor = darkColor //self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None self.tableView.delegate = self self.tableView.dataSource = self self.view.addSubview(self.tableView) //Set up text field self.textField = UITextField(frame: CGRectMake(0, 0, self.view.bounds.size.width, 100)) self.textField.backgroundColor = lightColor self.textField.font = UIFont(name: "AvenirNext-Bold", size: 26) self.textField.delegate = self self.view.addSubview(self.textField) } //Table View Delegate func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { return tableViewData.count } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { var myNewCell: MyTableViewCell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as MyTableViewCell myNewCell.text = self.tableViewData[indexPath.row] return myNewCell } func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) { let mySelectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath) //Colors mySelectedCell.detailTextLabel.textColor = UIColor.whiteColor() mySelectedCell.tintColor = UIColor.whiteColor() //Setup Details / Date let myDate:NSDate = NSDate() var myDateFormatter:NSDateFormatter = NSDateFormatter() myDateFormatter.dateStyle = NSDateFormatterStyle.MediumStyle mySelectedCell.detailTextLabel.text = myDateFormatter.stringFromDate(myDate) mySelectedCell.accessoryType = UITableViewCellAccessoryType.Checkmark mySelectedCell.backgroundColor = greenColor } override func prefersStatusBarHidden() -> Bool { return true } //Text Field Delegate func textFieldShouldReturn(textField: UITextField!) -> Bool { tableViewData.append(textField.text) textField.text = "" self.tableView.reloadData() textField.resignFirstResponder() return true } } And this is MyTableViewCell.swift: import UIKit class MyTableViewCell: UITableViewCell { let medColor: UIColor = UIColor(red: 0.973, green: 0.388, blue: 0.173, alpha: 1) init(style: UITableViewCellStyle, reuseIdentifier: String) { super.init(style: UITableViewCellStyle.Subtitle, reuseIdentifier: reuseIdentifier) self.textColor = UIColor.whiteColor() self.backgroundColor = medColor self.selectionStyle = UITableViewCellSelectionStyle.None } override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } } I am using iOS8 as deployment target (not sure of the difference it will make).
Add these two functions: func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if (editingStyle == UITableViewCellEditingStyle.Delete) { // handle delete (by removing the data from your array and updating the tableview) } } Swift 3.0: override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == UITableViewCellEditingStyle.delete) { // handle delete (by removing the data from your array and updating the tableview) } } Swift 4.2 func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == .delete) { // handle delete (by removing the data from your array and updating the tableview) } }
You can try this: func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == .delete) { NamesTable.beginUpdates() Names.removeAtIndex(indexPath.row) NamesTable.deleteRowsAtIndexPaths([indexPath], withRowAnimation: nil) NamesTable.endUpdates() } } If you're supporting iOS11+ please see the discussion: Use the performBatchUpdates(_:completion:) method instead of this one whenever possible.
Another way that allows you to change the text of "Delete" and add more buttons when sliding a cell is to use editActionsForRowAtIndexPath. func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } func tableView(tableView: (UITableView!), commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: (NSIndexPath!)) { } func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? { var deleteAction = UITableViewRowAction(style: .Default, title: "Delete") {action in //handle delete } var editAction = UITableViewRowAction(style: .Normal, title: "Edit") {action in //handle edit } return [deleteAction, editAction] } canEditRowAtIndexPath and commitEditingStyle are still required, but you can leave commitEditingStyle empty since deletion is handled in editActionsForRowAtIndexPath.
It's new feature in iOS11 and Swift 4. Reference link : Trailing Swipe : #available(iOS 11.0, *) override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, sourceView, completionHandler) in print("index path of delete: \(indexPath)") completionHandler(true) } let rename = UIContextualAction(style: .normal, title: "Edit") { (action, sourceView, completionHandler) in print("index path of edit: \(indexPath)") completionHandler(true) } let swipeActionConfig = UISwipeActionsConfiguration(actions: [rename, delete]) swipeActionConfig.performsFirstActionWithFullSwipe = false return swipeActionConfig }
import UIKit class ViewController: UIViewController ,UITableViewDelegate,UITableViewDataSource { var items: String[] = ["We", "Heart", "Swift","omnamay shivay","om namay bhagwate vasudeva nama"] var cell : UITableViewCell } #IBOutlet var tableview:UITableView override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { return self.items.count; } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { var cell = tableView.dequeueReusableCellWithIdentifier("CELL") as? UITableViewCell if !cell { cell = UITableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "CELL")} cell!.textLabel.text = self.items[indexPath.row] return cell } func tableView(tableView: UITableView!, canEditRowAtIndexPath indexPath: NSIndexPath!) -> Bool { return true } func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) { if (editingStyle == UITableViewCellEditingStyle.Delete) { // handle delete (by removing the data from your array and updating the tableview) if let tv=tableView { items.removeAtIndex(indexPath!.row) tv.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) } } } }
use it : func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == UITableViewCellEditingStyle.Delete { langData.removeAtIndex(indexPath.row) //langData is array from i delete values tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) } } hope it helps you
I used tableViewCell to show multiple data, after swipe () right to left on a cell it will show two buttons Approve And reject, there are two methods, the first one is ApproveFunc which takes one argument, and the another one is RejectFunc which also takes one argument. func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { let Approve = UITableViewRowAction(style: .normal, title: "Approve") { action, index in self.ApproveFunc(indexPath: indexPath) } Approve.backgroundColor = .green let Reject = UITableViewRowAction(style: .normal, title: "Reject") { action, index in self.rejectFunc(indexPath: indexPath) } Reject.backgroundColor = .red return [Reject, Approve] } func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func ApproveFunc(indexPath: IndexPath) { print(indexPath.row) } func rejectFunc(indexPath: IndexPath) { print(indexPath.row) }
Swift 4 -- #available(iOS 11.0, *) func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let edit = UIContextualAction(style: .normal, title: "") { (action, view, nil) in let refreshAlert = UIAlertController(title: "Deletion", message: "Are you sure you want to remove this item from cart? ", preferredStyle: .alert) refreshAlert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { (action: UIAlertAction!) in })) refreshAlert.addAction(UIAlertAction(title: "No", style: .default, handler: { (action: UIAlertAction!) in refreshAlert .dismiss(animated: true, completion: nil) })) self.present(refreshAlert, animated: true, completion: nil) } edit.backgroundColor = #colorLiteral(red: 0.3215686275, green: 0.5960784314, blue: 0.2470588235, alpha: 1) edit.image = #imageLiteral(resourceName: "storyDelete") let config = UISwipeActionsConfiguration(actions: [edit]) config.performsFirstActionWithFullSwipe = false return config }
As of Xcode 6.1.1, there are some tiny changes to Dash's answer. override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if (editingStyle == UITableViewCellEditingStyle.Delete) { // handle delete (by removing the data from your array and updating the tableview) } }
Swift 3: func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == UITableViewCellEditingStyle.delete) { // delete data and row dataList.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .fade) } }
Swift 3 with custom title supported func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } //If you want to change title func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? { return "Cancel" } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == UITableViewCellEditingStyle.delete) { // you might want to delete the item at the array first before calling this function tableView.deleteRows(at: indexPath, with: .automatic) } }
Works for me in Swift 2.0 override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { } override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? { let block = UITableViewRowAction(style: .Normal, title: "Block") { action, index in print("Block") self.removeObjectAtIndexPath(indexPath, animated: true) } let delete = UITableViewRowAction(style: .Default, title: "Delete") { action, index in print("Delete") self.removeObjectAtIndexPath(indexPath, animated: true) } return [delete, block] }
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? { let delete = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "DELETE"){(UITableViewRowAction,NSIndexPath) -> Void in print("What u want while Pressed delete") } let edit = UITableViewRowAction(style: UITableViewRowActionStyle.Normal, title: "EDIT"){(UITableViewRowAction,NSIndexPath) -> Void in print("What u want while Pressed Edit") } edit.backgroundColor = UIColor.blackColor() return [delete,edit] }
In Swift 4 tableview add, swipe to delete UITableViewCell func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { let delete = UITableViewRowAction(style: .destructive, title: "delete") { (action, indexPath) in // delete item at indexPath } return [delete] }
Swift 5 Since UITableViewRowAction was deprecated in iOS 13.0 so you can use UISwipeActionsConfiguration func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { (contextualAction, view, boolValue) in self.deleteData(at: indexPath) } let editAction = UIContextualAction(style: .normal, title: "Edit") { (contextualAction, view, boolValue) in self.editData(at: indexPath) } editAction.backgroundColor = .purple let swipeActions = UISwipeActionsConfiguration(actions: [deleteAction,editAction]) return swipeActions } func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func deleteData(at indexPath: IndexPath) { print(indexPath.row) } func editData(at indexPath: IndexPath) { print(indexPath.row) }
Swift 4 #available(iOS 11.0, *) func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let action = UIContextualAction(style: .normal, title: "", handler: { (action,view,completionHandler ) in //do stuff completionHandler(true) let data:NSDictionary = self.conversations[indexPath.row] as! NSDictionary print(data) let alert:UIAlertController = UIAlertController(title: "", message: "are you sure want to delete ?", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "CANCEL", style: UIAlertActionStyle.cancel, handler: { (action) in })) self.present(alert, animated: true, completion: nil) }) action.image = UIImage(named: "") action.backgroundColor = UIColor(red: 0/255, green: 148/255, blue: 204/255, alpha: 1.0) let confrigation = UISwipeActionsConfiguration(actions: [action]) return confrigation }
Simply add method: func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? { let delete = UITableViewRowAction(style: UITableViewRowActionStyle.destructive, title: "Delete") { (action, indexPath) in self.arrayFruit.remove(at: indexPath.row) self.tblList.reloadData() } let edit = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "Edit") { (action, indexpath) in let alert = UIAlertController(title: "FruitApp", message: "Enter Fuit Name", preferredStyle: UIAlertControllerStyle.alert) alert.addTextField(configurationHandler: { (textField) in textField.placeholder = "Enter new fruit name" }) alert.addAction(UIAlertAction(title: "Update", style: UIAlertActionStyle.default, handler: { [weak alert](_) in let textField = alert?.textFields![0] self.arrayFruit[indexPath.row] = (textField?.text!)! self.tblList.reloadData() })) self.present(alert, animated: true, completion: nil) } edit.backgroundColor = UIColor.blue return [delete,edit] }
For > ios 13 https://gist.github.com/andreconghau/de574bdbb468e001c404a7270017bef5#file-swipe_to_action_ios13-swift /* SWIPE to Action */ func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle { return .none } // Right Swipe func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let action = UIContextualAction(style: .normal, title: "Favourite") { [weak self] (action, view, completionHandler) in self?.handleMarkAsFavourite() completionHandler(true) } action.backgroundColor = .systemBlue return UISwipeActionsConfiguration(actions: [action]) } func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { // Archive action let archive = UIContextualAction(style: .normal, title: "Archive") { [weak self] (action, view, completionHandler) in self?.handleMoveToArchive() completionHandler(true) } archive.backgroundColor = .systemGreen // Trash action let trash = UIContextualAction(style: .destructive, title: "Trash") { [weak self] (action, view, completionHandler) in self?.handleMoveToTrash(book: (self?.books![indexPath.row]) as! BookItem) completionHandler(true) } trash.backgroundColor = .systemRed // Unread action let unread = UIContextualAction(style: .normal, title: "Mark as Unread") { [weak self] (action, view, completionHandler) in self?.handleMarkAsUnread() completionHandler(true) } unread.backgroundColor = .systemOrange let configuration = UISwipeActionsConfiguration(actions: [trash, archive, unread]) // If you do not want an action to run with a full swipe configuration.performsFirstActionWithFullSwipe = false return configuration } private func handleMarkAsFavourite() { print("Marked as favourite") } private func handleMarkAsUnread() { print("Marked as unread") } private func handleMoveToTrash(book: BookItem) { print("Moved to trash") print(book) let alert = UIAlertController(title: "Hi!", message: "Bạn có muốn xóa \(book.name)", preferredStyle: .alert) let ok = UIAlertAction(title: "Xóa", style: .default, handler: { action in book.delete() self.listBook.reloadData() }) alert.addAction(ok) let cancel = UIAlertAction(title: "Hủy", style: .default, handler: { action in }) alert.addAction(cancel) DispatchQueue.main.async(execute: { self.present(alert, animated: true) }) } private func handleMoveToArchive() { print("Moved to archive") }
SWIFT 3 -- UIViewController func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == UITableViewCellEditingStyle.delete) { // handle delete (by removing the data from your array and updating the tableview) print("delete tableview cell") } }
swift 3 func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == UITableViewCellEditingStyle.delete) { arrayCityName.remove(at: indexPath.row) self.tableCityName.reloadData() } }
just add these assuming your data array is 'data' func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if (editingStyle == UITableViewCellEditingStyle.delete) { // handle delete (by removing the data from your array and updating the tableview) if let tv=table { data.remove(at: indexPath.row) tv.deleteRows(at: [indexPath], with: .fade) } } }
func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? { let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in //handle like delete button print("share button tapped") } share.backgroundColor = .lightGray let delete = UITableViewRowAction(style: .normal, title: "Delete") { action, index in self.nameArray.remove(at: editActionsForRowAt.row) self.swipeTable.beginUpdates() self.swipeTable.deleteRows(at: [editActionsForRowAt], with: .right) self.swipeTable.endUpdates() print("delete button tapped") } delete.backgroundColor = .orange return [share,delete] } func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true }
#available(iOS 11.0, *) func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let editAction = UIContextualAction.init(style: UIContextualAction.Style.normal, title: "Edit", handler: { (action, view, completion) in //TODO: Edit completion(true) self.popUpViewPresent(index:indexPath.row) }) let deleteAction = UIContextualAction.init(style: UIContextualAction.Style.destructive, title: "Delete", handler: { (action, view, completion) in //TODO: Delete completion(true) self.deleteTagAction(senderTag:indexPath.row) }) editAction.image = UIImage(named: "Edit-white") deleteAction.image = UIImage(named: "Delete-white") editAction.backgroundColor = UIColor.gray deleteAction.backgroundColor = UIColor.red let config = UISwipeActionsConfiguration(actions: [deleteAction, editAction]) config.performsFirstActionWithFullSwipe = false return config }
Xcode asks for UIContextualAction, here what worked for me for the updated version: For Trailing Swipe Actions:-> func delete(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction { let company = companies[indexPath.row] let action = UIContextualAction(style: .destructive, title: "Delete") { (action, view, _) in // Perform Delete Action } return action } func edit(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction { let action = UIContextualAction(style: .normal, title: "Edit") { (action, view, escaping) in // Perform Edit Action } return action } override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let delete = self.delete(forRowAtIndexPath: indexPath) let edit = self.edit(forRowAtIndexPath: indexPath) let swipe = UISwipeActionsConfiguration(actions: [delete, edit]) return swipe } For Leading Swipe Actions:-> func delete(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction { let company = companies[indexPath.row] let action = UIContextualAction(style: .destructive, title: "Delete") { (action, view, _) in // Perform Delete Action } return action } func edit(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction { let action = UIContextualAction(style: .normal, title: "Edit") { (action, view, escaping) in // Perform Edit Action } return action } override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { let delete = self.delete(forRowAtIndexPath: indexPath) let edit = self.edit(forRowAtIndexPath: indexPath) let swipe = UISwipeActionsConfiguration(actions: [delete, edit]) return swipe } Return true for canEditRowAt for tableView Delegate:-> override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { return true }