ios - 图片下载后更新单元格高度

标签 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(), ^{

    // UIImageView resizing  
    });  
});

所有这一切都发生在 cellForRowAtIndexPath 中。
我在这里面临的问题是:
1.如何更新单元格的高度?考虑到单个单元格中可以有很多图像。所以我需要在上面一个下载时更改底部图像的位置。
2. 我尝试使用 UITableView beginUpdatesendUpdates,但滚动到单元格的顶部导致用户体验不佳。

这是用户界面在 reloadData 上的样子。有5张图片需要下载:UI experience after UITableView reloadData

最佳答案

简答

  • estimatedRowHeight 足够的呼吸空间
  • 一旦 dequeueReusableCellWithIdentifier 返回,更改 UITableViewCell用于缓存单元
  • 使用 reloadRowsAtIndexPaths 触发单个单元格重新加载
  • 使用 Core Data 管理您的缓存,让 NSFetchedResultsController 样板代码可以完成所有 UI 工作。

详情

没有意外的滚动,只在图片出现时更新:

  1. 如果正在刷新的单元格位于低于地平线,UITableView滚动<
  2. 如果正在刷新的单元格位于顶部上方UITableView滚动
  3. UITableView 只会在单元格清晰可见时滚动,并且需要比可用空间更多的空间。

UITableViewAutomaticDimension 完成繁重的工作

您需要告诉 Cocoa Touch 该单元格陈旧,以便它会触发一个 dequeueReusableCellWithIdentifier,您将前往返回具有适当高度的单元格
无需重新加载整个 TableView 或其部分之一,并假设您的索引稳定,调用 -tableView:reloadRows:at:with: 传递刚刚更改的单元格的 indexPath,然后.fade 动画。

代码:

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.estimatedRowHeight = 250 // match your tallest cell
    tableView.rowHeight = UITableViewAutomaticDimension
}

使用URLSession。当图像可用时,触发 reloadRows: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* 中随机获取一组图像

Xcode demo

► 在 GitHub 上找到此解决方案以及有关 Swift Recipes 的更多详细信息.

关于ios - 图片下载后更新单元格高度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33975355/

相关文章:

ios - 快速修改 tableViewController 之外的表

ios - 在 TableView 上显示具有特殊字符的联系人时遇到问题

ios - 将 UIImageView 放置在另一个具有缩放功能的上方

ios - 软阴影,SceneKit 中的阴影模糊

ios - CIDetector iOS 64 位 "No suitable image found"

ios - 我可以在不使用 -all_load 链接器标志的情况下使用适用于 iOS 的 adMob 库吗

iphone - 触摸位置、框架。 CGRectContainsPoint 不返回 true

ios - Swift CLAuthorizationStatus.AlwaysAuthorized 未定义

ios - 在 iOS 8 和 swift 中更改 UITableViewCell 字体

ios - 为什么 UIImageView 没有使用 Swift 正确加载