Подход, который в итоге работал гладко, был:
Шаг 1. Сохранение в переменной UITableViewCell под панелью навигации и сохранение смещения этой ячейки относительно панели навигации.
Шаг 2. Вставьте ячейки / reloadData.
Шаг 3. Перейдите к ячейке, которую мы сохранили перед вставкой / перезагрузкой, а затем добавьте смещение.
Вот код:
UIView.performWithoutAnimation {
//Step 1 Detect & Store
let topWillBeAt = getTopVisibleRow() + countOfAddedItems
let oldHeightDifferenceBetweenTopRowAndNavBar = heightDifferenceBetweenTopRowAndNavBar()
//Step 2 Insert
self.tableView.insertRows(at: arrayOfIndexPaths, with: .none)
//Step 3 Restore Scrolling
tableView.scrollToRow(at: IndexPath(row: topWillBeAt, section: 0), at: .top, animated: false)
tableView.contentOffset.y = tableView.contentOffset.y - oldHeightDifferenceBetweenTopRowAndNavBar
}
И вспомогательные функции:
func getTopVisibleRow () -> Int {
//We need this to accounts for the translucency below the nav bar
let navBar = navigationController?.navigationBar
let whereIsNavBarInTableView = tableView.convert(navBar!.bounds, from: navBar)
let pointWhereNavBarEnds = CGPoint(x: 0, y: whereIsNavBarInTableView.origin.y + whereIsNavBarInTableView.size.height + 1)
let accurateIndexPath = tableView.indexPathForRow(at: pointWhereNavBarEnds)
return accurateIndexPath?.row ?? 0
}
func heightDifferenceBetweenTopRowAndNavBar()-> CGFloat{
let rectForTopRow = tableView.rectForRow(at:IndexPath(row: getTopVisibleRow(), section: 0))
let navBar = navigationController?.navigationBar
let whereIsNavBarInTableView = tableView.convert(navBar!.bounds, from: navBar)
let pointWhereNavBarEnds = CGPoint(x: 0, y: whereIsNavBarInTableView.origin.y + whereIsNavBarInTableView.size.height)
let differenceBetweenTopRowAndNavBar = rectForTopRow.origin.y - pointWhereNavBarEnds.y
return differenceBetweenTopRowAndNavBar
}