I have a list of data that I\'m pulling from a web service. I refresh the data and I want to insert the data in the table view above the current data, but I want to keep my
None of the answers here really worked for me, so I came up with my solution. The idea is that when you pull down to refresh a table view (or load it asynchronously with new data) the new cells should silently come and sit on top of the tableview without disturbing the user's current offset. So here goes a solution that works (pretty much, with a caveat)
var indexpathsToReload: [IndexPath] = [] //this should contain the new indexPaths
var height: CGFloat = 0.0
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
UIView.performWithoutAnimation {
self.tableview.reloadSections(NSIndexSet(index: 0) as IndexSet, with: .none)
self.tableview.layoutIfNeeded()
indexpathsToReload.forEach({ (idx) in
height += self.feed.rectForRow(at: idx).height
})
let afterContentOffset = self.tableview.contentOffset
let newContentOffset = CGPoint(x: afterContentOffset.x, y: afterContentOffset.y + height)
self.tableview.setContentOffset(newContentOffset, animated: false)
}
}
CAVEAT (WARNING)
This technique will not work if your tableview is not "full" i.e. it only has a couple of cells in it. In that case you would need to also increase the contentSize
of the tableview along with the contentOffset
. I will update this answer once I figure that one out.
EXPLANATION:
Basically, we need to set the contentOffset
of the tableView
to a position where it was before the reload. To do this we simply calculate the total height of all the new cells that were added using a pre populated indexPath
array (can be prepared when you obtain the new data and add them to the datasource), these are the indexPaths
for the new cells. We then use the total height of all these new cell using rectForRow(at: indexPath)
, and set that as the y
position of the contentOffset
of the tableView
after the reload. The DispatchQueue.main.asyncAfter
is not necessary but I put it there because I just need to give the tableview some time to bounce back to it's original position since I am doing it on a "pull to refresh" way. Also note that in my case the afterContentOffset.y
value is always 0
so I could have hard coded 0
there instead.