iOS 11 UITableView delete rows animation bug

video of the tableview animation bug

I have a table view which expands/collapse its cells.

As of iOS 11, the tableView starts to behave strangely on insertion and deletion of rows. The contentSize has changed before the animation block happens and consequently, in the video, you can see a buggy scroll back happening on collapsing cells. The animation just looks wrong.

This code worked perfectly on iOS 10. Do anyone know what has changed on Apple's side? Is this a known issue?

public func insertingRowsForAccordion(_ indexArray: [IndexPath], selectedRowIndex: Int) {
    beginUpdates()
    insertRows(at: indexArray, with: UITableViewRowAnimation.fade)
    endUpdates()

 // Scroll to selection after expanding children
    scrollToRow(at: IndexPath(row: selectedRowIndex, section: 0), at: UITableViewScrollPosition.top, animated: true)
}

public func removeRowsForAccordion(_ indexArray: [IndexPath]) {
    beginUpdates()
    deleteRows(at: indexArray, with: UITableViewRowAnimation.fade)
    endUpdates()
}

Answers


I have been having countless problems with iOS 11 UITableView. Going to every UITableView in my entire app and doing the following fixed all of my problems.

Set estimatedRowHeight, estimatedSectionHeaderHeight, and estimatedSectionFooterHeight to 0.

Source: iOS 11 Floating TableView Header


I had similar problem with table row removal animation on iOS 11 sometimes scrolling the table cells strangely (iOS 10 worked just fine). What helped was implementing this delegate method returning row height:

- (CGFloat) tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

After that both iOS 10 and 11 work just fine.


In iOS 11.2, I had a bad animation after deleting a row using the standard row actions. I was only able to improve the situation by wrapping the row delete and row action dismissal in a CATransaction.

I dismiss the row actions first and wait for that animation to complete before deleting the row from the table view.

It at least doesn't jump around the table views content offset anymore, but is a lengthy two step animation. I'm still looking for a better solution.

        CATransaction.begin()
        CATransaction.setCompletionBlock({
            self.tableView.beginUpdates()
            self.myViewModel?.items?.remove(at: indexPath.row)
            self.tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.top)
            self.tableView.endUpdates()
        })
        self.tableView.setEditing(false, animated: true)
        CATransaction.commit()

I fixed it by using this code:

self.tableView.beginUpdates()
// ...
self.tableView.endUpdates()
self.tableView.layer.removeAllAnimations()

Need Your Help