I have the following problem. When I delete UITableViewCells from my UITableView with "swipe to delete" I see an ugly behaviour of the UITableView. Regardless which animation I choose in the deleteRows method all deletions result in the same strange behaviour.
This is my code for deleting the cell
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.tvItems.beginUpdates()
if(indexPath.section == 0){
Shoppingcart.shared.removeItemForId(ident: indexPath.row)
}else if (indexPath.section == 1){
Shoppingcart.shared.serviceContent.remove(at: indexPath.row)
}
if let parent = self.parent as? CollectionViewController{
parent.collectionView?.reloadData()
}
self.tvItems.deleteRows(at: [indexPath], with: .fade)
self.tvItems.endUpdates()
}
}
Here is an image of the broken animation:
I found a solution for my problem. The tableviewcell hight estimation was set on automatic. I did set the hight on the same as the row height and the broken animation disappeared.
Settings for the broken animation:
Settings for the working animation:
I had A LOT of trouble with this. Moving completion(true) to the top instead of at the bottom solved the problem. Hope it helps someone out there!
alert.addAction(UIAlertAction(title: "Delete", style: .destructive) { (action) in
completion(true) // *** PUT THIS HERE!!! ****
self.searchFoodView.beginUpdates()
self.foodMachine.deleteFood(at: indexPath.row - 1)
self.searchFoodView.deleteRows(at: [indexPath], with: .fade)
self.searchFoodView.endUpdates()
})
Related
I'm having trouble removing the last cell I have tried tableView.reloadData() and beginUpdate(), endUpadate(), and all these methods works fine if I have more than one cell, but when I come to deleting the last cell it didn't work and the tableView won't reloadData at the same time that I delete the last cell, other cells 2-3-4 no problem, Plus when I close the app everyThing works fine.
im deleting the cells from the firebase store its a document that contains data if concern
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
print("Deleted")
self.DriverOffers.remove(at: indexPath.row)
self.DriverOrdersTV.deleteRows(at: [indexPath], with: .automatic)
self.DriverOrdersTV.reloadData()
}else if editingStyle == .insert {
self.DriverOrdersTV.beginUpdates()
self.DriverOrdersTV.insertRows(at: [IndexPath.init(row: 0, section: 0)], with: .automatic)
self.DriverOrdersTV.endUpdates()
}
}
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
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
}
I have a requirement where I need to show a tableview with three rows always.
When user swipes to delete a row, I need to add a new row at the bottom.
While this happens, the swipe animation which moves the row to the left to delete has to be retained. I mean delete animation should not be affected. Is this possible?
First, your dataSource must return always 3 for your numberOfRows(in:) method. Then you can commit changes this way:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
tableView.performBatchUpdates({
// Delete the swiped row
tableView.deleteRows(at: [indexPath], with: .left)
// Get the last row index (numberOfRows-1)
let lastRowIndex = tableView.numberOfRows(inSection: indexPath.section)-1
// Insert a new row at the end
tableView.insertRows(at: [IndexPath(row: lastRowIndex, section: 0)], with: .top)
}, completion: nil)
}
}
Don't forget to update the rest of your dataSource accordingly, because cells may be reused. The code need to be added before call performBatchUpdates. Something like that:
var cellsText = ["A","B","C"]
// Inside your tableView(:commit:forRowAt) method:
if editingStyle == .delete {
cellsText.remove(at: indexPath.row)
cellsText.append("D")
// ...
}
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.