Section headers "bounce" when UITableView is reloaded

Viewed 936

I have a UITableView which under goes a batch update when the state of app changes. The change can effect a number of rows/sections or only one section (but 1 or more rows).

I've noticed that when under going a single section update (which may effect a number of rows in the section), the section headers for the other sections "bounce" or are "moved" from their previous position and then animated back into place.

A picture paints a thousand words...

Video Capture

These sections are not part of the batch update.

The UITableView/Controller is setup through a story board targeting iOS 11. The UITableView is making use of the "Estimated" row and section heights and the cells are laid out using auto layout.

Xcode storyboard properties

The UITableViewController makes use of a larger data model which managers the state and state change operations. The API ensures that the required updates are calculated based on the required state of the model (i.e. deletes and updates relate to the "previous" state, inserts related to the "new" state)

The last step is to apply the calculated changes to the table view through a batch update process...

tableView.beginUpdates()

// Calculate the rows/sections which need to be changed

if let ops = operation.sections[.delete], ops.count > 0 {
    tableView.deleteSections(ops, with: deleteSectionAnimation)
}
if let ops = operation.sections[.update], ops.count > 0 {
    tableView.reloadSections(ops, with: reloadSectionAnimation)
}
if let ops = operation.sections[.insert], ops.count > 0 {
    tableView.insertSections(ops, with: insertSectionAnimation)
}

if let ops = operation.rows[.delete], ops.count > 0 {
    tableView.deleteRows(at: ops, with: deleteRowAnimation)
}
if let ops = operation.rows[.update], ops.count > 0 {
    tableView.reloadRows(at: ops, with: reloadRowAnimation)
}
if let ops = operation.rows[.insert], ops.count > 0 {
    tableView.insertRows(at: ops, with: insertRowAnimation)
}
tableView.endUpdates()

tableView.reloadData()
tableView.layoutIfNeeded()

The row and section animation properties (i.e. deleteSectionAnimation) are set to automatic. I've tried setting the section animations to none without any differences

I've tried removing the reloadData and layoutIfNeeded in varying combinations and while they create other issues, they don't seem to come close to resolving this issue

One thing I've noticed, is this only seems to occur when the updates occurring to the UITableView are been done off screen

I've spend some time trying to find a solution to the issue (like not calling reloadData) but can't find something which works.

Is there some other property, function I should look at or is the order in which the updates are been executed wrong?

Notes

  • This is a "static" table, setup through storyboards
  • The rows and sections are been added/removed during state changes, which seems to trigger issues/changes in the scroll view
  • While disabling animation (with UIView.setAnimationsEnabled) does seem to fix the issue, it's an undesirable solution, as it removes the animations for all updates (on or off screen)
  • The issue only occurs when the scroll view is NOT at the top of the view, updates/animations occurring when the table view is scrolled all the way to the top have no issues
  • I've tried using indexPathsForVisibleRows to determine if the updates are occurring on or off the screen, and disable the animation using UIView.setAnimationsEnabled but it doesn't solve the issue if the update occurs on the screen while the table view is not scrolled to the top of the scroll view
0 Answers
Related