Swipe to delete animation overlaps with other tableview cells - ios

I have installed a swipe-to-delete function in my tableview. Nothing special there. However, when performed, the red delete button (row action) overlaps while retracting to the right with the cell below even though the deleted cell has already disappeared.
In the editActionsForRowAt function I first remove the value from the array and then from a reference in Firebase. Here is the code:
func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .normal, title: "Verwijder") { action, index in
tableView.beginUpdates()
let item = self.joinedArrayFiltered[editActionsForRowAt.section][editActionsForRowAt.row]
let indexPath: IndexPath = IndexPath(row: editActionsForRowAt.row, section: editActionsForRowAt.section)
self.joinedArrayFiltered[editActionsForRowAt.section].remove(at: editActionsForRowAt.row)
self.ref.child("productsObserver").child(item.productId).child("wishlistUsers").child(self.userID).removeValue()
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.bottom)
tableView.endUpdates()
}
delete.backgroundColor = .red
return [delete]
}
To help visualize the issue, please see the attached GIF below.
Any suggestions would be helpful, thanks.

Related

UITableView's deleting animation does not work properly

When I trying to delete a row in UITableview, the list move up 2 rows and the animation behavior is also strange, as you could see 2 "Water:11" cells appears(moves down)... How's that going on? I use swift with a Xcode version 9.4.1, and here is my delete code:
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let deleteAction = UITableViewRowAction(style: .destructive, title: "DELETE") { (action, actionIndexPath) in
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .automatic)
Results.remove(at: indexPath.row)
tableView.endUpdates()
}
return [deleteAction]
}
a GIF that shows what's going on
When tableview didn't get row height properly this kind of issue occur. To fix that you just need to give estimated row height. Thanks

EditActionForIndexPath is displaying action for wrong row

I am using editActionsForRow method in the UITableViewDelegate. It's displaying the action for the wrong row.
I also used trailingSwipeActionConfiguration method but it didn't work.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let archiveAction = UIContextualAction(style: .normal, title: "Archive") { (action, customView, completion) in
self.tableData.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
The action view shows up on the wrong row if I try to swipe two rows one by one.

Is there a way to know when a UITableViewCell is removed from UITableView?

I am showing a UITableView which is driven by RxRealmDataSources.
I need to perform some actions when a row in the table gets deleted.
Is there a way such that whenever a row gets deleted from the table, a function gets called with the indexpath of the deleted row?
Edit -
The UI of a cell of the UITableView in my app depends on 2 things -
A data object that is fetched from the realm db ( info )
The index position of the row
Whenever, a cell gets deleted, I need to update the UI of its next cell.
If the only way the db ever got updated was by the direct action of the user, then I could have used func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) method to get the indexPath of the cell that should be deleted and update the UI of the next cell.
However, the db is synced to cloud and the db is binded to the table view so that I do not have control on when cells gets added or deleted. It is for this reason, I wanted to know if there is a way to know when a cell is removed from UITableView
Due to the reusability of cells in UITableView, cells are not actually deleted until the table itself is deallocated.
I might assume that by 'deleting' cell you mean cell disappearing from the screen. In this case the following function of UITableViewDelegate might help you (called when the cell is not visible any more):
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
In a comment you said:
By 'deleting', I mean when the cell is removed from the tableview like when we swipe the cell to the left to remove it.
Since you tagged RxSwift, the solution is to use itemDeleted as in:
tableView.rx.itemDeleted
.subscribe(onNext: { print("delete item at index path \($0) from your model.")})
.disposed(by: bag)
If you aren't looking for an Rx solution, then your question is a dup of:
Add swipe to delete UITableViewCell
I was able to solve this by subclassing the UITableView class and overriding the func deleteRows(at indexPaths: [IndexPath], with animation: UITableView.RowAnimation) method.
You have to implement 1 delegate method of UITableView.
trailingSwipeActionsConfigurationForRowAt
It's easy to implement. This delegate method will be called twice, one when you swipe and again when you press to delete a row.
`enter code here`
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let config = UISwipeActionsConfiguration(actions: [makeDeleteContextualAction(forRowAt: indexPath)])
config.performsFirstActionWithFullSwipe = true
return config
}
private func makeDeleteContextualAction(forRowAt indexpath:IndexPath) -> UIContextualAction {
let deleteAction = UIContextualAction(style: .destructive, title: LocalizableConstants.constLS_global_delete()) { (action, swipeButtonView, completion) in
let product = self.products[indexpath.row]
if let quantity = product.vo_quantity(), let amount = product.vo_priceFide() {
self.totalProducts -= Int(truncating: quantity)
self.totalAmount -= amount.doubleValue * quantity.doubleValue
}
DispatchQueue.main.async {
self.lbBasketNumber.text = String(self.totalProducts)
self.lbTotalAmount.text = String(self.totalAmount)
}
self.products.remove(at: indexpath.row)
self.tableView.deleteRows(at: [indexpath], with: .fade)
if #available(iOS 13.0, *) {
action.image = ImagesConstants.constIMG_XCA_mini_icon_red_trash()
action.image?.withTintColor(ConstantsColor.const_COLOR_RED())
action.backgroundColor = ConstantsColor.const_COLOR_WHITE()
} else {
action.title = LocalizableConstants.constLS_global_delete()
}
completion(true)
}
return deleteAction
}

Deleting row (or array item) permanently - swift 3/4

After successfully deleting a row from UITableView, I go to another view controller but when I return to the UITableView the deleted row is back again. Am I missing something? I am relatively new to Swift.
Here is the code:
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) in
self.queuelayout.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
print(self.queuelayout)
}
return [delete]
}
I've also tried with this code:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete{
queuelayout.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .right)
}
}
Look forward to your help.
I checked your top codes. They are all right. The only possible reason is as you said you went to another VC , you have already get rid of your tableViewController from the memory. Here is an simple example:
If your tableView is the most right one, and when you go back to middle vc, your right one will be removed from the memory. Then when you click assign button and actually, you are loading a completely new tableViewController.
As a result, viewDidLoad will be called and your tableViewController will init again to the original states.
You may set a breakpoint at func viewDidLoad(), to check this situation. If this one is not called when you go back, you are good to go. Otherwise, everything will be reset. All what you delete will reappear as they should.
This is a simple example. Your case may be a little complicated. But if your tableviewcontroller called ViewDidLoad(), you must have some hassles somewhere.
Hope this help you out.

Swift 3 how to have delete cell button like iOS mail application (image and text )

like this
How can I have a swipe delete cell button like iOS mail application(image + text )?
I found this method but my image is not scale to size:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let deleteButton = UITableViewRowAction(style: .Destructive, title:"\nDelete", handler: { (action, indexPath) in
self.tableView.dataSource?.tableView?(self.tableView,commitEditingStyle: .Delete,
forRowAtIndexPath: indexPath)
return
})
deleteButton.backgroundColor = UIColor(patternImage: UIImage(named: "icon")!)
return [deleteButton]
}
thanks in advance
I am little confused with your explanation. If you can please provide some more explanation regarding button you want. Do you want Standard button which iOS provides itself or you want a customize button?
I am trying to address both aspects below.
If you need standard operation you can do it like this:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// remove the item from the array if you want
array.remove(at: indexPath.row)
// delete the table view row
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
}
Also, i would like to recommend This.
If u just want to resize button image you can do it like this:
deleteButton.imageView?.contentMode = UIViewContentMode.scaleAspectFill
The table view will do that for you. You just need to have your table view/table view controller live in a navigation stack so there's a navigation bar, and then implement a couple of methods: tableView(_, canEditRowAt:) and tableView(_:,commit:forRowAt:).
You'll probably want to add an edit button to your navigation bar.
I just pushed a demo project called MasterDetailSwift that supports adding and removing cells to a table view. (It also shows the master/detail UI pattern, a good way to handle prepareForSegue using a switch statements, and a few other useful techniques.)

Resources