UITableView insert rows without scrolling

前端 未结 6 1389
我在风中等你
我在风中等你 2020-12-05 03:13

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

6条回答
  •  眼角桃花
    2020-12-05 03:43

    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.

提交回复
热议问题