Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eternal scrolling UITableView

I'm trying to create a UITableView with dates, shouldn't be very exciting, I know. It starts around the current date, but the user should be able to scroll down (the future) and up (the past) as far as he/she wants. This results in a potentially infinite number of rows. So what's the way to go about creating this?

Returning NSIntegerMax as the number of rows already crashes the app, but even if it wouldn't, that still doesn't account for being able to scroll up. I could start half way of course, but eventually there's a maximum.

Any ideas how to do or fake this? Can I update/reload the table somehow without the user noticing, so I never run into a border?

SOLUTION:
I went with @ender's suggestion and made a table with a fixed amount of cells. But instead of reloading it when the user scrolls to near the edges of the fixed cells, I went with reloading the table when the scrolling grinds to a halt. To accomodate with a user scrolling great distances without stopping, I just increased the row count to 1000, putting the ROW_CENTER constant to 500. This is the method that takes care of updating the rows.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    NSArray *visible = [self.tableView indexPathsForVisibleRows];
    NSIndexPath *upper = [visible objectAtIndex:0];
    NSIndexPath *lower = [visible lastObject];

    // adjust the table to compensate for the up- or downward scrolling
    NSInteger upperDiff = ROW_CENTER - upper.row;
    NSInteger lowerDiff = lower.row - ROW_CENTER;

    // the greater difference marks the direction we need to compensate
    NSInteger magnitude = (lowerDiff > upperDiff) ? lowerDiff : -upperDiff;

    self.offset += magnitude;
    CGFloat height = [self tableView:self.tableView heightForRowAtIndexPath:lower];
    CGPoint current = self.tableView.contentOffset;
    current.y -= magnitude * height;
    [self.tableView setContentOffset:current animated:NO];

    NSIndexPath *selection = [self.tableView indexPathForSelectedRow];
    [self.tableView reloadData];
    if (selection)
    {
        // reselect a prior selected cell after the reload.
        selection = [NSIndexPath indexPathForRow:selection.row - magnitude inSection:selection.section];
        [self.tableView selectRowAtIndexPath:selection animated:NO scrollPosition:UITableViewScrollPositionNone];
    }
}

The magic breaks when a user scrolls to the edge of the table without stopping, but with the table view bounces property disabled, this merely feels like a minor glitch, yet totally acceptable. As always, thanks StackOverflow!

like image 546
epologee Avatar asked Sep 20 '11 15:09

epologee


3 Answers

You should establish a fixed number of cells and adjust your datasource when the user scrolls near the end of the tableview. For example, you have an array with 51 dates (today, 25 future and 25 past). When the app tries to render a cell near one of the borders, reconfigure your array and call reloadData

like image 50
Youssef Avatar answered Oct 26 '22 02:10

Youssef


You might also have a look at the "Advanced Scroll View Techniques" talk of the WWDC 2011. They showed how you would create a UIScrollView which scrolls indefinitely. It starts at about 5 mins. in.

like image 45
nesium Avatar answered Oct 26 '22 02:10

nesium


Two thoughts:

  1. Do you really need a UITableView? You could use a UIScrollView, three screens high. If end of scrolling is reached, layout your content and adjust scrolling position. This gives the illusion of infinite scrolling. Creating some date labels and arranging them in layoutSubviews: should not be too much of an effort.

  2. If you really want to stick to UITableView you could think about having two UITableViews. If scrolling in your first one reaches a critical point, spin off a thread and populate the second one. Then at some point, exchange the views and trigger the scrolling manually so that the user does not note the change. This is just some idea from the top of my head. I have not implemented something like this yet, but I implemented the infinite UIScrollView.

like image 29
Krumelur Avatar answered Oct 26 '22 02:10

Krumelur