I've been testing an app with people and after I tell them they can swipe to delete they find it intuitive but up front not everyone - in my experience at least - is savvy enough to figure it out.
Is there an alternative? I think ideally i'd like to have a little trash can or "x" on the the tableView cell that can be pressed to delete. But not sure that is easily implemented.
The first issue I encountered is I don't think I can drag an IBOutlet from a TableViewCell to the UIViewController where I have my table view.
And even if that is possible not sure how I would implement the below function when the delete button is clicked.
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
So was just wondering if swipe to delete is my only option?
Thanks.
You can do this for implementing the "x" button on the the tableView cell:
protocol CustomCellDelegate {
func removeButtonTappedOnCell(with indexPath: IndexPath)
}
class CustomCell: UITableViewCell {
var delegate: CustomCellDelegate?
#IBOutlet weak var removeButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
#IBAction func removeButtonTapped(_ sender: UIButton) {
let indexPath = IndexPath(row: sender.tag, section: 0)
delegate?.removeButtonTappedOnCell(with: indexPath)
}
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CustomCellDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.removeButton.tag = indexPath.row
cell.delegate = self
return cell
}
func removeButtonTappedOnCell(with indexPath: IndexPath) {
modelArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .right)
}
}
What you are describing is usually achieved by putting an 'Edit' button into one side of the Navigation Bar. The button puts the table into an edit mode that allows tapping of small, red delete buttons. Just another way to do the same thing, i.e. delete a row. Create a Master-Detail app from the iOS template and see how the button is created programmatically in the viewDidLoad method. Then look at the following methods that handle the deletion, whether initiated by a swipe or the Edit button.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
objects.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
Related
There is a UITableView that uses UITableViewDiffableDataSource. I subclassed UITableViewDiffableDataSource to add canEditRowAt. This correctly shows the swipeable delete action when gesturing the row. However, clicking the delete option does not call tableView(_:commit:forRowAt:). I have read that you have to use tableView(_:trailingSwipeActionsConfigurationForRowAt:indexPath:) because the other function is not supported. I wanted to confirm that was true. If we subclass tableView(_:commit:forRowAt:) as well, we need a clean way to call a function on the original View Controller.
// MyViewController
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete cell
}
}
// Subclass DiffableDataSource used in MyViewController
final class CustomDiffableDatasource: UITableViewDiffableDataSource<MyViewController.Section, MyViewController.Item> {
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
guard let item = itemIdentifier(for: indexPath) else {
return false
}
return item.isEditable
}
}
Here is the custom trailingSwipeActionsConfigurationForRowAtfunc looks like for adding a delete swipe. I saw this in another StackOverflow question that referenced a blog post.
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
guard self.dataSource?.tableView(tableView, canEditRowAt: indexPath) == true else {
return nil
}
let delete = UIContextualAction(style: .destructive, title: "Delete") { [weak self] action, view, success in
self?.remove(at: indexPath)
success(true)
}
let swipeActionConfig = UISwipeActionsConfiguration(actions: [delete])
swipeActionConfig.performsFirstActionWithFullSwipe = false
return swipeActionConfig
}
I am using JSON to parse data from Spotify and add songs into a UITableView. The songs play fine, and I added functionality for deleting cells, but when adding functionality for reording cells, I can''t play songs and I can't swipe to delete them either. Any ideas would be appreciated.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.tableView.isEditing = true
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
This adds the album image and song name to the TableView.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
let mainImageView = cell?.viewWithTag(2) as! UIImageView
mainImageView.image = posts[indexPath.row].mainImage
let mainLabel = cell?.viewWithTag(1) as! UILabel
mainLabel.text = posts[indexPath.row].name
return cell!
}
This adds the swipe to delete functionality.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
posts.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .none
}
override func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
This adds the reordering functionality.
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedObject = self.posts[sourceIndexPath.row]
posts.remove(at: sourceIndexPath.row)
posts.insert(movedObject, at: destinationIndexPath.row)
debugPrint("\(sourceIndexPath.row) => \(destinationIndexPath.row)")
self.tableView.reloadData()
}
You don't want to set
self.tableView.isEditing = true
in viewDidLoad. This takes you from the "normal" mode where you can select a cell, or other elements in a cell. Setting "self.tableview.isEditing" is the equivalent of hitting an edit button on the top right-hand corner of many tableViews.
There aren't very many tutorials for this for Swift 5.1 and I am pretty novice. I am wondering how to make the tableView delete override func work for my code. It gives me an error on objects because they are an unresolved identifier. Also what would go in the insert?
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
let mainImageView = cell?.viewWithTag(2) as! UIImageView
mainImageView.image = posts[indexPath.row].mainImage
let mainLabel = cell?.viewWithTag(1) as! UILabel
mainLabel.text = posts[indexPath.row].name
return cell!
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
objects.remove(at: indexPath.row) // Here I get an error because objects is an unresolved identifier.
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. I am also confused as to what goes here.
}
}
All of the information you will need can be found here.
This method allows the delegate to customize the editing style of the cell located atindexPath. If the delegate does not implement this method and the UITableViewCell object is editable (that is, it has its isEditing property set to true), the cell has the UITableViewCell.EditingStyle.delete style set for it.
This is what you are missing:
https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614869-tableview
override func tableView(_ tableView: UITableView,
editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
return .delete
}
Here you are using an object to remove data for the index path which is wrong you are using "posts" named array to show values on the table view. So, this "posts" array contains objects which are visible on the table view.
So, here when you want to remove object then this means you have to remove objects from the "posts" array. Below the attached function with some changes, you can check this it will work for you.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
posts.remove(at: indexPath.row) // Here I get an error because objects is an unresolved identifier.
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
posts.append("Here insert what you want") //inside append you can append/insert values to the array
tableView.reloadData()
}
}
How can i create info button on the right side for editing the content along with the deletion control(left side) whenever i click edit button?
(something like this)
`
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
objects.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}`
Use accessoryType.
In cellForRowAt method, add
cell.editingAccessoryType = .detailButton
and Give action to it by
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
print("Accessory btn tapped")
}
I need pan gesture like editingStyle in Swift, but I need this gesture for whole row and on end of gesture do action, which delete the cell.
I don't know, how to do it, because I am beginner. I know, that I must use UIGestureRecognizer, but I don't know how to do with that. I found some options, but all of that was only for delete without animation and I need animation and background for swiping.
I have only this code for show dynamic data:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TasksCell", for: indexPath) as! TasksCell
let arrayTasks = tasks[indexPath.row]
cell.taskName.text = arrayTasks.content
return cell
}
Can you help me with that?
You can use UITableView Delegate method to delete row. No need to use Pan Gesture. Please try this
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool
{
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == .delete
{
yourArray.remove(at: indexPath.row)
yourTableView.reloadData()
}
}