重新加载行以更新 UITableView 中的单元格高度时出现问题
Posted
技术标签:
【中文标题】重新加载行以更新 UITableView 中的单元格高度时出现问题【英文标题】:Problems when reloading rows to update cell height in UITableView 【发布时间】:2014-09-24 11:12:32 【问题描述】:我有一个自定义的UITableViewCell
,我使用AFNetworking
将来自URL 的UIImageView
中的图像设置为。加载图像后,我想调整图像视图和单元格的大小以适合图像。
在我的tableView:cellForRowAtIndexPath:
我有以下代码:
FeedItem *feedItem = self.dataArray[indexPath.row];
FeedItemCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"FeedItemCell" forIndexPath:indexPath];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:feedItem.thumbnailUrl];
[request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
[cell.thumbnailImageView setImageWithURLRequest:request placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image)
cell.thumbnailImageView.image = image;
// first I set the height of the image view
cell.thumbnailImageHeightConstraint.constant = image.size.height;
// then I save the height in a dictionary to return it in tableView:heightForRowAtIndexPath:
[thumbnailHeights setObject:[NSNumber numberWithFloat:thumbnailHeight] forKey:[NSNumber numberWithInteger:indexPath.row]];
// now I reload the cell in order to have the new height applied
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error)
NSLog(@"failed loading: %@", error);
];
在我的tableView:heightForRowAtIndexPath:
我有这个:
NSNumber *thumbnailHeightNumber = [thumbnailHeights objectForKey:[NSNumber numberWithInteger:indexPath.row]];
if (thumbnailHeightNumber != nil) // image size has been calculated
return thumbnailHeightNumber.floatValue;
return 0;
这类作品。在图像视图和单元格上都正确设置了高度。但是,有一些不可预知的行为:
-
当我滚动时,某些单元格有时会闪烁,好像正在重新加载,这很烦人。
有时会在行中显示错误的单元格。实际上,
tableView:cellForRowAtIndexPath:
返回的单元格的内容是正确的,但它显示了来自之前一个单元格的内容。
有时单元格是完全空白的。同样,检查其内容似乎是正确的。
我注意到了一些可能与该问题相关的内容。我的 tableView:cellForRowAtIndexPath:
方法总是被调用两次,我相信这实际上是导致我的问题的原因。如果我删除[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
行,它只被调用一次(对于每一行)并且问题停止,但是当然单元格的高度不会更新。
另外,我不认为这个问题与单元格高度的实际变化有关。如果我为图像和单元格高度设置了固定高度,调用reloadRowsAtIndexPaths:withRowAnimation:
时仍然会得到相同的副作用。
因此,我希望有解决此问题的方法,或通过其他方式来实现我的动态单元格高度目标。
【问题讨论】:
【参考方案1】:对setImageWithURLRequest:request:placeholderImage:success:failure:
的调用是异步的,因此cell.thumbnailImageView
将不会被填充,或者(如果正在重新使用单元格)在setImageWithURLRequest
成功之前将有以前的图像数据,可能在@987654324 之后的一段时间@ 已经返回了单元格。如果setImageWithURLRequest
失败,那么您的单元格将保留未更改/未配置的缩略图视图。
您可以在placeholder:
参数中提供一个图像,该图像将在调用success
块之前一直显示,那么至少您还有一个失败案例的后备方案。
一段时间后,随着各个单元格的成功块被异步调用,表格可能会闪烁,每个单元格都会强制重新加载不同的行。
除非您事先知道缩略图都是固定大小的(然后可以轻松使用标准占位符图像),否则我建议您在表格视图的 numberOfRowsInSection:
更改其返回值之前预加载相关的缩略图从而触发对tableView:cellForRowAtIndexPath:
的调用。这样您就可以在单元格中返回完全配置的图像。
【讨论】:
我理解你关于异步执行的观点,但这是我在互联网上发现人们的做法,包括AFNetworking
提供的示例。在我写的时候,如果我忽略对reloadRowsAtIndexPaths:withRowAnimation:
的调用,问题就不会发生,并且图像加载得很好(在正确的行中)。不幸的是,我不知道图像的大小,因此不知道整个练习。我不确定按照您的建议预加载图像是一个好主意,因为我不想加载所有图像。 tableView:cellForRowAtIndexPath:
仅在单元格即将变得可见时调用。
是的,关于不想不必要地预加载所有图像的好处。是否可能没有在主线程上调用 reloadRowsAtIndexPaths:withRowAnimation: ?
好吧,我想这是可能的,因为它是从完成块内部调用的。以上是关于重新加载行以更新 UITableView 中的单元格高度时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
在 UITableView (swift2) 中选择单元格时更新/重新加载 ViewController
UITableView 在同一批次更新中重新加载和移动行导致“尝试为单元格创建两个动画”
UITableView, reloadData 重新加载单元格但不调整表格大小