ios - 在 tableView 中重新加载后保持滚动位置

标签 ios objective-c uitableview uiscrollview uiscrollviewdelegate

我有一个 tableView。当用户点击其中一条记录时,我会检查它的属性并基于此过滤结果并仅显示类似的结果 - 因此我需要刷新 tableView。

问题是用户可以向上/向下滚动 tableView。我需要滚动 tableView,以便单元格与刷新前的 UITableViewScrollPosition 完全相同。

显然,我正在保存最后点击的项目

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

然后在重新加载 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;
}

这很好,但是......用户无法在 UITableViewScrollPositionMiddle 处完成。他本可以在 UITableViewScrollPositionTopUITableViewScrollPositionBottom 或什至介于两者之间的某个位置完成滚动。

-- 编辑--

通过偏移量计算也是有问题的,因为偏移量是 View 开始和顶部表格滚动位置之间的差异。虽然我对此值不感兴趣:/。

最佳答案

因为我的结构很复杂,所以我就这样完成了(例如,可扩展部分等)。请注意,我正在保存 _lastSelectedItem,这是我在数据源中的对象,因为刷新后 indexPath 会发生变化。

- (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;
        }
    }
}

关于ios - 在 tableView 中重新加载后保持滚动位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26011304/

相关文章:

ios - iOS模拟器:从终端终止所有应用

ios - facebook iOS SDK 授权,无需重定向到 safari

ios - 在 Swift 中创建 PDF

iphone - 查看不显示更新的 xib

ios - 滚动时 TableView 上的复选标记重复

ios - 在 Objective-C 中从网站获取 HTML 数据 - 解析 HTML

objective-c - iOS – AppDelegate 作为实例变量?

iphone - 将通配 rune 件名从主包复制到文档?

iphone - 在 UITableView 中使用 UITableViewCell

ios - UIView "stealing"从 UITableView 触摸