1
votes

I have a feed that gets populated with 15 posts from the server. When I scroll down to 3 before the end of the list, I ping the server for the next 15 posts. This functionality works great. However, when I start scrolling up, the UITableViewCells frequently jump up, as though Cell 5 is now populating Cell 4, and Cell 4 is now populating Cell 3, etc. Either that, or the UITableView scroll is just jumping up.

When I get to the very top of the UITableView and then proceed to scroll down through all my data then back up, it works perfectly though. Is there a drawing issue with my table?

Edit: So, I've come across the understanding that this is happening because the heights of all my cells are dynamic. I'm pretty sure as I'm scrolling up, my UITableView is calculating and setting the appropriate heights, which is causing the jumpy action. I'm not sure how to mitigate that.

2
I wouldn't expect much help. Unfortunately these problems are nearly impossible to debug if you can't run the actual project. You have to sprinkle println() on all of your scrolling and tableDataSource methods and look at things like the contentOffset and the requested indexPaths of the table. Once you have figured out what exactly happens while the glitch happens you are halfway there.Matthias Bauch
Just another suggestion if this is iOS8 - don't put a nested view in the cell's content view, but instead put your content directly in the content view. I had a very similar problem which I resolved in this way.GuybrushThreepwood
@GuybrushThreepwood I'm not sure I understand what you meanDavid
The contents of your cell. Are they in a view within the cell's content view ?GuybrushThreepwood
The contents of my cell are directly within the ContentView, not a View.David

2 Answers

0
votes

I never used the new funcionality of dynamic cell size in iOS8, but I can give you few suggestion for improve performance on table views. It should be a comment but it doesn't fit.

  • Cache the height of cells already displayed if you can. It's easy an dictionary paired with a sort of id would do the trick
  • Pay attention that you do not have complex layout between subviews of you cells
  • Check if you are drawing something that requires offscreen rendering, such as corner radius, clipping etc

I don't know how dynamic cell works on ios8 but I share piece of my code. It's pretty straightforward. I have a cell that I use as prototype, each times I need to calculate a cell height I feed it with my data, that I force it's layout to get me the correct height. Once I've got the height I saved it in a NSDictionary using the postID(it's a twitter like app) as a key.
This happens only when the cell height is not cached. If it is cached the height is returned.

- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGSize  size = CGSizeZero;
    NSDictionary * data = self.timelineData[indexPath.row];
    if (data[KEY_CELL_IDENTIFIER] == CellIdentifierPost) {
        NSNumber * cachedHeight = [self.heightCaches objectForKey:@([(AFTimelinePostObject*)data[KEY_CELL_DATA] hash])];//[(AFTimelinePostObject*)data[KEY_CELL_DATA] timelinePostObjectId]];
        if (cachedHeight) {
            return (CGFloat)[cachedHeight doubleValue];
        }
        [_heightCell configureCellWith:data[KEY_CELL_DATA]];
        size = [_heightCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
        [self.heightCaches setObject:@(size.height) forKey:@([(AFTimelinePostObject*)data[KEY_CELL_DATA] hash])];//[(AFTimelinePostObject*)data[KEY_CELL_DATA] timelinePostObjectId]];
    }
    else if (data[KEY_CELL_IDENTIFIER] == CellIdentifierComment){
        NSNumber * cachedHeight = [self.heightCaches objectForKey:@([(AFTimelinePostComments*)data[KEY_CELL_DATA] hash])];//[(AFTimelinePostObject*)data[KEY_CELL_DATA] timelinePostObjectId]];
        if (cachedHeight) {
            return (CGFloat)[cachedHeight doubleValue];
        }
        [_heightCommentCell configureCellWith:data[KEY_CELL_DATA]];
        size = [_heightCommentCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
        if (size.height < 80.0f) {
            size = (CGSize) {
                .width = NSIntegerMax,
                .height = 115.f
            };
        }
        else if (size.height > 180.0f) {
            size = (CGSize) {
                .width = NSIntegerMax,
                .height = 180.f
            };
        }

        [self.heightCaches setObject:@(size.height) forKey:@([(AFTimelinePostComments*)data[KEY_CELL_DATA] hash])];//[(AFTimelinePostObject*)data[KEY_CELL_DATA] timelinePostObjectId]];

    }
    else {
        size = (CGSize) {
            .width = NSIntegerMax,
            .height = 50.f
        };
    }

    return size.height;
}
0
votes

Unfortunately, there does not seem to be a simple answer to this. I have struggled with it on multiple iOS apps.

The only solution I have found is to programmatically scroll to the top of your UITableView once it appears again.

[self.tableView setContentOffset:CGPointMake(0, 0 - self.tableView.contentInset.top) animated:YES];

OR

self.tableView.contentOffset = CGPointMake(0, 0 - self.tableView.contentInset.top);

Hope this an acceptable work around while still being able to use dynamic cell heights =)