3

I've got a tableView. When user taps one of records, I check it's property and basing on this I'm filtering results and showing only similar results - so I need to refresh the tableView.

The problem is that user can scroll up/down the tableView. I need to scroll the tableView so the cell is exactly at the same UITableViewScrollPosition as before the refresh.

Obviously, I'm saving last tapped item

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    _lastSelectedItem = [self itemForIndexPath:indexPath];
} 

Then after reloading the tableView:

NSIndexPath *indexPath = [self indexPathForItem:_lastSelectedItem];
if (_tableView.numberOfSections > indexPath.section && [_tableView numberOfRowsInSection:indexPath.section] > indexPath.row) {
    [_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
    _lastSelectedItem = nil;
}

It would be good but... user could not finish at UITableViewScrollPositionMiddle. He could have finish scrolling at UITableViewScrollPositionTop or UITableViewScrollPositionBottom or even somewhere between.

-- edit --

Calculating via offset is also problematic, as the offset is the difference between start of view and top table scroll position.. while I'm not interested in this value :/.

Nat
  • 12,032
  • 9
  • 56
  • 103

1 Answers1

0

Because my structure was quite complicated I finished to do it this way (eg. expandable sections etc). Please do mind, that I'm saving _lastSelectedItem, which is my object at datasource, as indexPath will change after refresh.

- (void)refresh {
    [self saveLastScrollPosition];
    [self reloadData]; // inside we reload data + reload tableView
    [self scrollToLastScrollPosition];
}

- (NSInteger)heightToMinYOfCellAtIndexPath:(NSIndexPath *)indexPath {
    NSInteger sections = indexPath.section;
    NSInteger totalRows = 0;
    for (NSInteger section = 0; section < indexPath.section; section++) {
        totalRows += [self.tableView numberOfRowsInSection:section];
    }
    totalRows += indexPath.row;

    return ((sections + 1) * kHeaderHeight + totalRows * kRowHeight);
}

- (void)saveLastScrollPosition {
    if (_lastSelectedItem) { // make sure we have that item selected
        NSIndexPath *indexPath = [self itemForItem:_lastSelectedItem];
        NSInteger aboveItemHeight = [self heightToMinYOfCellAtIndexPath:indexPath];
        CGFloat contentOffsetY = self.tableView.contentOffset.y;
        _previousOffset = aboveItemHeight - contentOffsetY;
    }
}

- (void)scrollToLastScrollPostion {
    if (_lastSelectedItem) { // make sure we have that item selected
        NSIndexPath *indexPath = [self itemForItem:_lastSelectedItem];
        if (self.tableView.numberOfSections > indexPath.section && [self.tableView numberOfRowsInSection:indexPath.section] > indexPath.row) { // make sure the indexPath still exist after reload
            NSInteger aboveItemHeight = [self heightToMinYOfCellAtIndexPath:indexPath]; // height of items above selected index
            CGPoint offset = CGPointMake(0.f, aboveItemHeight - _previousOffset);
            // in case index should be higher: eg earlier item was at index (4,8) now is at (0,0)
            if (offset.y < 0) {
                offset.y = 0;
            }
            [self.tableView setContentOffset:offset animated:NO]; // just jump, user shouldn't see this
            _previousOffset = 0; // forget the calculated values
            _lastSelectedItem = nil;
        }
    }
}
Nat
  • 12,032
  • 9
  • 56
  • 103
  • 1
    It could be put into a UITableView category with a single 'reloadDataAndScrollToLastPosition' public method. – Balazs Nemeth Jan 07 '15 at 16:54
  • if suppose uitableview cell height dynamic and also header is also dynamic and we will used multiple custom cell so what will we can do please explain it............. – Jatiendar Kumar Oct 25 '15 at 13:30
  • @JatiendarKumar Explain Depends how did you implement it. You may look at http://www.raywenderlich.com/73602/dynamic-table-view-cell-height-auto-layout, in about middle of the page you can see such method `heightForBasicCellAtIndexPath:` and take it as your example. – Nat Oct 26 '15 at 10:00
  • This is a duplicate post: http://stackoverflow.com/a/18844780/3705567 - WORKS! (Y) – A. Trejo May 24 '16 at 18:06