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
Related
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.
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
}
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.
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()
})
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.