UITableView重新加载时滚动到顶部

20
我在我的应用程序中遇到了问题 - 您可以发布和编辑您最喜爱的地点。在发布帖子或编辑特定帖子(UITableViewCell)(UITableViewCell)之后,UITableview 会重新加载。
我的问题是: 在重新加载后,UITableview 滚动到顶部。但这不是我想要的。我希望我的视图停留在我所在的单元格/视图上。但我不知道如何管理它。
你能帮帮我吗?

1
你看过UITableView的方法:reloadRowsAtIndexPaths吗? - Dominic
请查看以下答案:https://dev59.com/Tl4c5IYBdhLWcg3wVpBI,当您重新加载时,可能需要保存您正在查看的索引以知道要滚动到哪里。 - Tyler Pierog
6个回答

24

如果你使用动态调整大小的单元格(UITableViewAutomaticDimension),那么Igor的答案是正确的。

在Swift 3中,这里是示例:

    private var cellHeights: [IndexPath: CGFloat?] = [:]
    var expandedIndexPaths: [IndexPath] = []

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cellHeights[indexPath] = cell.frame.height
    }

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if let height = cellHeights[indexPath] {
            return height ?? UITableViewAutomaticDimension
        }
        return UITableViewAutomaticDimension
    }


    func expandCell(cell: UITableViewCell) {
      if let indexPath = tableView.indexPath(for: cell) {
        if !expandedIndexPaths.contains(indexPath) {
            expandedIndexPaths.append(indexPath)
            cellHeights[indexPath] = nil
            tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
            //tableView.scrollToRow(at: indexPath, at: .top, animated: true)
        }
      }
    }

令人惊讶的是,这对我有所帮助,而且我没有使用动态单元格高度。谢谢! - Paul Lehn
1
是的,当您使用编程方式添加动态行高度时,此代码非常有用。我正在从textview文本计算行高度。重新加载tableview时会出现小问题。添加此代码将消除这个小问题。 - prateek sharma
expandCell()方法的目的是什么,我无法理解它。它只是用于演示还是我在我的代码中也需要使用它? - Asad Ali Choudhry

16
为了防止页面滚动到顶部,您应该在单元格加载时保存它们的高度,并在tableView:estimatedHeightForRowAtIndexPath方法中提供精确的值:
// declare cellHeightsDictionary
NSMutableDictionary *cellHeightsDictionary;

// initialize it in ViewDidLoad or other place
cellHeightsDictionary = @{}.mutableCopy;

// save height
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    [cellHeightsDictionary setObject:@(cell.frame.size.height) forKey:indexPath];
}

// give exact height value
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSNumber *height = [cellHeightsDictionary objectForKey:indexPath];
    if (height) return height.doubleValue;
    return UITableViewAutomaticDimension;
}

这个可以运行,但是你能解释一下为什么只用heightForRowAt还不够吗? - DeyaEldeen
1
这适用于表视图在向下滚动时的情况。但在向上滚动时不起作用。您能否提供一些建议,可能出了什么问题? - Gautam Shrivastav
你的意思是编程上滚动到某个indexPath,跳过前面的几行吗?如果是的话,你可以预先计算高度。 - Igor
遇到了与@Gautam Shrivastav相同的问题,当滚动到顶部并在顶部加载新行时,它会自动滚动到新数据的顶部,而不是保持在最后可见的单元格上。 - Asad Ali Choudhry

10

UITableViewreloadData()方法是显式地强制重新加载整个tableView。它可以很好地工作,但通常会打扰用户体验和使用一个用户当前正在查看的表格视图。

相反,可以看一下reloadRowsAtIndexPaths(_:withRowAnimation:)reloadSections(_:withRowAnimation:)文档中的链接


这两种方法有时会触发完全重新加载。 - Dave

6

如果您想要一个简单的解决方案,只需使用这些代码行。

let contentOffset = tableView.contentOffset
tableView.reloadData()
tableView.setContentOffset(contentOffset, animated: false)

-2

在Swift 3.1中

DispatchQueue.main.async(execute: {

    self.TableView.reloadData()
    self.TableView.contentOffset = .zero

})

1
@OsamaBinBashir 不是真的,但你必须在主线程上调用这些方法。 - Eduardo Irias
@EduardoIrias 同意这个观点 :) - osama

-4

现在使用 Swift 5,我们可以通过简单的 tableview.reloadDataAndKeepOffset() 来实现。


没有reloadDataAndKeepOffset()这样的东西。 - Wahab Khan Jadon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接