Ios 下载图像后更新单元格高度

Ios 下载图像后更新单元格高度,ios,uitableview,uiimageview,grand-central-dispatch,Ios,Uitableview,Uiimageview,Grand Central Dispatch,我正在UITableView中显示一些文本和图像。首先下载图像。因为在下载图像之前,我不知道图像的大小,所以我首先放置了一个固定大小的UIImageView。下载图像时,我会调整UIImageView的大小 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Download image dispatch_async(dispatch_get_main_queue(),

我正在
UITableView
中显示一些文本和图像。首先下载图像。因为在下载图像之前,我不知道图像的大小,所以我首先放置了一个固定大小的
UIImageView
。下载图像时,我会调整
UIImageView
的大小

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// Download image

    dispatch_async(dispatch_get_main_queue(), ^{

    // UIImageView resizing  
    });  
});
所有这些都发生在
cellforrowatinexpath

我在这里面临的问题是:
1.如何更新单元格的高度?考虑到单个单元格中可能有多个图像。因此,当上面的图片下载时,我需要更改底部图片的位置。

2.我尝试使用
UITableView
beginUpdates
endUpdates
,但这会滚动到单元格顶部,用户体验不佳

这就是重新加载数据时UI的外观。有5张图片需要下载:

简短回答
  • 给予足够的喘息空间,以
    EstimateDroweight
  • 一旦
    dequeueReusableCellWithIdentifier
    返回一个
    UITableViewCell
    ,更改该
    UITableViewCell将使用缓存的单元格
  • 使用reloadRowsAtIndexPaths
  • 使用核心数据管理缓存,让
    NSFetchedResultsController
    样板代码完成所有UI工作

详细地 无意外滚动,只在图像出现时更新图像:

  • 如果正在刷新的单元格位于地平线以下,则
    UITableView
    滚动
  • 如果正在刷新的单元格位于顶部上方,则
    UITableView
    滚动
  • UITableView
    仅在单元格清晰可见且所需空间大于可用空间时才会滚动
  • UITableViewAutomaticDimension
    做艰苦的工作

    您需要告诉Cocoa Touch该单元格已过时,这样它将触发一个新的
    ,您将返回一个具有适当高度的单元格。
    除了重新加载整个表视图或它的一个部分,并假设索引是稳定的,调用
    -tableView:reloadRows:at:with:
    传递刚刚更改的单元格的indexath,以及
    .fade
    动画

    代码:

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.estimatedRowHeight = 250 // match your tallest cell
        tableView.rowHeight = UITableViewAutomaticDimension
    }
    
    使用
    URLSession
    。当图像可用时,激发
    重新加载rows:at:with

    func loadImage(_ url: URL, indexPath: IndexPath) {
        let downloadTask:URLSessionDownloadTask =
            URLSession.shared.downloadTask(with: url, completionHandler: {
            (location: URL?, response: URLResponse?, error: Error?) -> Void in
            if let location = location {
                if let data:Data = try? Data(contentsOf: location) {
                    if let image:UIImage = UIImage(data: data) {
                        self.cachedImages[indexPath.row] = image // Save into the cache
                        DispatchQueue.main.async(execute: { () -> Void in
                            self.tableView.beginUpdates()
                            self.tableView.reloadRows(
                                at: [indexPath],
                                with: .fade)
                            self.tableView.endUpdates()
                        })
                    }
                }
            }
        })
        downloadTask.resume()
    }
    
    进入缓存后,
    cellForRow
    仅从UI线程读取:

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: "id") as! CustomCell
        cell.imageView.image = cachedImages[indexPath.row]      // Read from the cache
        return cell
    }
    

    示例:从*Wikipedia获取一组随机图像*


    ► 在上找到此解决方案,并在上找到其他详细信息。

    beginUpdates
    endUpdates
    在这种情况下无效。文档中说,实际上您不应该在组内调用重载数据。@HarikrishnanT:是的。用户界面体验差。我曾经遇到过同样的问题。问题是,如果只重新加载一行,它下面的单元格将隐藏在它后面,因为它的帧不会改变。我使用重新加载的数据使其稳定,然后,它工作顺利。不确定你的UX问题是什么。@HarikrishnanT:请检查我在链接上上传的视频。它显示了重新加载数据时的UI体验。为什么不使用
    reloadRowsAtIndexPaths:withRowAnimation:
    ?在这种情况下,我是否需要调用HeightForRowatinex?否。您将在链接的Xcode项目中看到,不需要任何传统高度计算。自动布局完成所有工作。这很神奇。如果我是对的,表格单元格的代码中还没有实现自动布局。这是否表明,我需要使用自动布局创建单元子视图才能工作?或者这不是必需的。加上一个示例代码。这是我想要的,应该的。但是,如果您想澄清上述注释,则在提供新单元格时,将调用传统方法,包括
    heightforrowatinexpath
    。但是,这种虚假的滚动是由于在交换单元格时,表视图不知道该放在哪里造成的。我只能说
    estimatedRowHeight
    +
    UITableViewAutomaticDimension
    组合来防止这种闪烁。