UITableView由带有UITableViewAutomaticDimension的FetchedResultsController提供 - 当表重新加载时单元格移动

时间:2015-05-07 16:45:13

标签: ios objective-c uitableview autolayout

当前设置:

具有自动计算高度的TableView:

self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 152.0;
self.tableView.estimatedSectionHeaderHeight = 50.0;

每当获取的结果控制器更新其数据时,都会重新加载tableview:

 - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView reloadData]; 
}

使用Xib配置单元格。第一个标签固定在单元格的顶部,每个标签固定在其上方标签的顶部,底部的标签固定在单元格的底部。

问题:

每次在表视图中的项目上设置“收藏夹”属性时,将触发提取的结果控制器以重新加载表格并更改滚动位置。这是我想要解决的滚动位置的这种变化。

其他信息

如果我使用固定的单元格高度它解决了问题但是我需要UITableViewAutomaticDimension,因为第一个标签可以包裹两行,其余标签可能存在也可能不存在。

示例

注意 - 当我选择Fav按钮时,它在Core数据中设置fav属性并重新加载表。桌子为什么跳来跳去?

enter image description here

1 个答案:

答案 0 :(得分:8)

这是因为以下顺序:

  1. UITableView初始化并显示5个单元格。 UITableView知道每个单元格的高度。在通过调用方法-tableView:heightForRowAtIndexPath:显示每个单元格之前,它会询问其代表的确切高度。
  2. UITableView从顶部完全滚动了3个单元格。已知该细胞的高度正好是[60,70,90] = 220。 UITableView的contentOffset.y现在是220。
  3. UITableView被重新加载。它清除了所有关于细胞的知识。它现在仍然知道它的contentOffset.y是220。
  4. UITableView询问有关常规指标的数据来源 - 每个部分的部分数量和行数。
  5. UITableView现在开始填充其内容。首先,它需要知道其内容的大小,以正确地调整其滚动指示器的大小和位置。它还需要知道哪些对象 - 表格标题,节标题,行,节页脚和表格页脚 - 它应根据其当前bounds显示,哪个位置也由contentOffset表示。要开始放置那些可见对象,首先需要跳过落在[0 ... 220]的不可见垂直范围内的对象。

    1. 如果您没有为任何estimated…属性提供值并且未实现任何tableViewController:estimated…方法,则UITableView会通过调用适当的委托来询问其委托有关页眉,页脚和行的确切高度的信息诸如-tableView:heightForRowAtIndexPath:之类的方法。如果您的委托报告与重新加载之前相同数量的对象和相同的高度,那么您将看不到任何表格元素的位置和大小的任何视觉上的变化。当你的表显示大量行时,这个“海峡”行为的下行变得明显,比方说50000.UITableView向其代表询问这50000行中每一行的高度,你必须自己通过测量每个对应的文本来计算它。对象,或者当使用UITableViewAutomaticDimension UITableView进行同样的测量时,向其委托询问填充文本的单元格。相信我,它很慢。每次重新加载都会导致几秒钟的界面冻结。
    2. 如果您提供了具有估计高度的UITableView,那么它将仅询问其代理当前可见对象的高度。垂直范围为[0 ... 220]的对象通过使用estimatedRowHeight-tableView:estimatedHeightForRowAtIndexPath:中为行提供的值以及用于节页眉和页脚的相应方法来计算。通过将estimatedRowHeight设置为60,您可以告诉UITableView跳过三行(60 * 3 = 180)并将第4行与顶部可见边缘的偏移量设置为-40。因此视觉上“跳跃”了40个像素。
  6. 这里的“正确”解决方案不是致电reloadData。仅为已更改的对象重新加载行,使用-reloadRowsAtIndexPaths:withRowAnimation:。如果是NSFetchedResultsController + UITableView,请使用此classic scheme