I'm building a simple chat UI into my app but I'm having trouble with scrolling when prepending cells.
As the user scrolls up near the top I trigger a background load to get additional chat messages. When these arrive I prepend them (add them to the top of the table view).
The problem I'm seeing is that when the new cells come in, the table view scrolls all the way to the top.
What I'd like is that the user's position and scrolling direction/velocity doesn't get interrupted at all when the new cells are added.
I've read countless posts about this and I've tried all the proposed solutions (contentOffset reset, estimatedRowHeight caching, reloadData, insertRow, etc) but none seem to quite work.
Most solutions out there are for situations where cells are added to the bottom of the table view. This works fine because the contentOffset
isn't affected when you reloadData
. But when prepending cells to the top there's no way to know the new total height of all new cells that got added.
I should mention that I'm using self-sizing cells with dynamic heights. The cells contain dynamic text that could be multiple lines long.
In order to eliminate any possible quirks with the rest of my app I've created a simple stripped down app to illustrate the problem.
You can check it out on github and try it out yourselves: github.com/nebs/pagination-scroll-test.
The app simply simulates an infinite list of fake messages. When you scroll all the way to the top it loads and prepends more fake messages (with a 2 second simulated delay). All the code is in ViewController.swift
You can ignore most of the boilerplate code. The main part of interest is in this line at the reloadTableView() function.
The "best" (so far) solution I have is Attempt #4 (see code). Here, I simply remember the top-most rendered message, then scroll to that message again. It kind of works, but if the user is mid-scroll it will jitter a bit because it doesn't scroll exactly to where the user was.
The other 3 attempts in my code don't work (the table view jumps to the top after the new cells are added).
I'm curious to hear what solutions others have found for this. It seems like a trivial problem on paper but I've been at this for many days with no clear solution in sight.
What's the current best practice for solving this? Specifically for tableviews where (dynamic, variable-height, self-sizing) cells are prepended at the top while the user is scrolling.
I thank you all in advance for any tips you can provide!