I've previously implemented deletion for cells in my UITableView by using the following code:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
feedTable.deleteRows(at: [indexPath!], with: .fade)
}
}
However, now I want to add a custom action for the cells so I've added this:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let edit = UITableViewRowAction(style: .normal, title: "Edit", handler: { (action, indexPath) in
})
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
}
edit.backgroundColor = UIColor.green
return [delete, edit]
}
Now I'm confused whether I even need the original commit editingStyle function. Should I just move all my editing handling code (feedTable.deleteRows(at: [indexPath!], with: .fade)) to the new function?
It seems to me like there are many different functions that have to do with UITableViewCell editing and I'm confused about which ones to use when.
Should I just move all my editing handling code (feedTable.deleteRows(at: [indexPath!], with: .fade)) to the new function?
The answer to your question : Yes
When you implement the tableView( _: editActionsForRowAtIndexPath: ) method, the table view will no longer generate the Delete button for you. This is why you need to create your own Delete button.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let edit = UITableViewRowAction(style: .normal, title: "Edit", handler: { (action, indexPath) in
// your handling code
})
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
// your handling code
}
// buttons colors
edit.backgroundColor = UIColor.green
delete.backgroundColor = UIColor.red
return [delete, edit]
}
Related
How to disable swipe left triggering deleteAction? I need it to be invoked only by tapping delete button.
I have this code for providing actions.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction(style: .destructive, title: "Delete", handler: { _, indexPath in
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .left)
tableView.endUpdates()
})
return [deleteAction]
}
Tried this fix but it didn't work.
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
if tableView.isEditing {
return .delete
}
return .none
}
Found the solution. I used trailingSwipeActionsConfigurationForRowAt method instead of editActionsForRowAt and there is a property performsFirstActionWithFullSwipe on a UISwipeActionsConfiguration which can be disabled.
I have had a UITableView working for several version of Swift, but with Swift 5, it started presenting 'delete' action on a left swipe.
One of the rows is 'swipe-able' (the 'Expanded' one) and others are not, so I return a nil in place of the RowAction.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
if listOfCurrentAwards[indexPath.row] != "Expanded" {
print(">>> Skipping row \(indexPath.row)")
return nil
} else {
let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
self.prepareOneDogMessageShareSheet(row: indexPath.row)
}
share.backgroundColor = UIColor.blue
return [share]
}
}
I am also getting the same behavior with the older 'editActionsForRowAtIndexPath'.
Anyone else seeing the same thing? Did you find a work around?
For now I am just returning a dummy action that displays a dog related emoji ().
if listOfCurrentAwards[indexPath.row] != "Expanded" {
//TBD - remove the following line if the nill action is supported/fixed.
let dogEmoji = ["🐶","🐩","🦴","🐕","💩","🐾"]
let share = UITableViewRowAction(style: .normal, title: dogEmoji.randomElement()) { action, index in
print(">>> Skipping row \(indexPath.row)")
}
return [share] //nil
} else ...
Update 1
Even refactoring to use trailingSwipeActionsConfigurationForRowAt did not work, I'm getting the same result.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
if listOfCurrentAwards[indexPath.row] != "Expanded" {
print(">>> Swiping not enabled for row \(indexPath.row)")
return nil
} else {
print(">>> 'Share' swipped on \(indexPath.row)")
let shareAction = UIContextualAction(style: .normal, title: "Share") { (action, view, handler) in
print(">>> 'Share' clicked on \(indexPath.row)")
self.prepareOneDogMessageShareSheet(row: indexPath.row)
}
shareAction.backgroundColor = UIColor.blue
let configuration = UISwipeActionsConfiguration(actions: [shareAction])
configuration.performsFirstActionWithFullSwipe = true //false to not support full swipe
return configuration
}
}
Answer
I had to add the canEditRowAt helper, allow me to move some of the logic from trailingSwipeActionsConfigurationForRowAt.
func tableView(_ tableView: UITableViewbcgdfgdfg, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?vdfgh
{
print(">>> Trying to swipe row \(indexPath.row)")
let shareAction = UIContextualAction(style: .normal, title: "Share") { (action, view, handler) in
print(">>> 'Share' clicked on \(indexPath.row)")
self.prepareOneDogMessageShareSheet(row: indexPath.row)
}
shareAction.backgroundColor = UIColor.blue
let configuration = UISwipeActionsConfiguration(actions: [shareAction])
return configuration
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return listOfCurrentAwards[indexPath.row] == "Expanded"
}
editActionsForRowAt is outmoded if the goal is to control what happens when you swipe. So is UITableViewRowAction.
You should be using tableView(_:trailingSwipeActionsConfigurationForRowAt:).
I am a beginner at Swift 3. I have a Table View, and the user can delete a table view cell. Now I want the user to be able to change the content of the cell. I have an array that contains four names ["Stremmel", "Emma", "Sam", "Daisy"] and I want the user to be able to say edit Stremmel to George.
I searched for documentation or a similar question that could help me to figure a way to do so, but I got more confused. Can someone please provide me with some help!! Thank you. Here is my table view:
import UIKit
var list = ["Stremmel" , "Emma" , "Sam" , "Daisy"]
class ViewController: UITableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return list.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = list[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete
{
list.remove(at: indexPath.row)
tableView.reloadData()
}
}
If you want to show Edit button also with Delete button then you need to implement editActionsForRowAt method with canEditRowAt method instead of commit editingStyle.
After that with editActionsForRowAt show AlertController with textField and update its value and reload the row. So remove or comment the commit editingStyle method from your code and add below two methods.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let editAction = UITableViewRowAction(style: .default, title: "Edit", handler: { (action, indexPath) in
let alert = UIAlertController(title: "", message: "Edit list item", preferredStyle: .alert)
alert.addTextField(configurationHandler: { (textField) in
textField.text = self.list[indexPath.row]
})
alert.addAction(UIAlertAction(title: "Update", style: .default, handler: { (updateAction) in
self.list[indexPath.row] = alert.textFields!.first!.text!
self.tableView.reloadRows(at: [indexPath], with: .fade)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: false)
})
let deleteAction = UITableViewRowAction(style: .default, title: "Delete", handler: { (action, indexPath) in
self.list.remove(at: indexPath.row)
tableView.reloadData()
})
return [deleteAction, editAction]
}
Normally when creating a UITableViewController() class, you should have some template code that provides a edit-button and a delete-function (should be included in the edit button)! Just uncomment it, it should be accessible then!
or you could just call self.editButtonItem() in the viewDidLoad()-function.
I'm sorry for my bad English, I hope that answered you question!
I'm implementing custom editActionsForRowAt actions for my tableView how do I make the slided cell come back to its normal state when tapped done, here is my code for the ViewController.
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
list.remove(at: indexPath.row)
list2.remove(at: indexPath.row)
tableView.reloadData()
}
let done = UITableViewRowAction(style: .normal, title: "Done") { (action, indexPath) in
let cell=tableView.cellForRow(at: indexPath) as! CustomCell
cell.makeanimate()
}
share.backgroundColor = UIColor.lightGray
return [delete, done]
}
my CustomCell has the makeanimate() function. I want the cell to slide back to its normal position when I tap the done action.
You should use the setEditing(_:animated:) function on the UITableView:
tableView.setEditing(false, animated: Bool)
You can read more on the function in Apple's documentation here: https://developer.apple.com/reference/uikit/uitableview/1614876-setediting
In my app I have a tableView in witch I have default text and I would like to have a swipe to edit text function so the user can change the text if the want to.
I already added the swipe to delete, using the code below, however adding an editing text function isn't as easy to find information on, So my question is, How can I add a button so the user can edit the text via a swipe function?
I need to know the code to load the text as I can't have a textfield so it's not as easy as something like label.text = textfield.text
the code that original loads the text is as follows
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
cell.textLabel?.text = places[indexPath.row]["name"]
Thanks !
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
places.removeAtIndex(indexPath.row)
NSUserDefaults.standardUserDefaults().setObject(places, forKey: "places")
tableView.reloadData()
}
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
var editAction = UITableViewRowAction(style: .Normal, title: "Edit") { (action, indexPath) in
tableView.editing = false
// your action
}
editAction.backgroundColor = UIColor.grayColor()
var deleteAction = UITableViewRowAction(style: .Default, title: "Delete") { (action, indexPath) in
tableView.editing = false
// your delete action
}
return [deleteAction, editAction]