【问题标题】:How to update tableview cell after async image download and resized image height异步图像下载和调整图像高度后如何更新表格视图单元格
【发布时间】:2018-09-12 16:15:53
【问题描述】:

如何在使用 Kingfisher setImage with completion handler 方法从服务器下载图像后更新单元格高度?图像下载后,我使用以下命令调整其高度约束:cell.imageHeight.constant = image.size.height * cell.frame.size.width / image.size.width

图像是在cellForRow 方法上下载并设置的,但我也在willDisplayCell 中尝试过,同样的问题。我还在 setImage 方法的完成处理程序中检查了cell.tag == indexPath.row

我已经尝试了以下方法,但都没有奏效:

  • heightForRowUITableViewAutomaticDimensionestimatedHeightForRowAt 是某个值(可能的最大单元格)以及这 2 个的所有其他组合
  • tableview 开始/结束更新
  • reloadRows 在 indexPath
  • cell.setNeedsLayoutlayoutIfNeededlayoutSubviews
  • dispatch main async

它们中的任何一个都遇到相同的问题:滚动时跳动的表格,第一次显示时单元格高度错误并更新它我必须上下滚动以隐藏和显示该单元格,某些单元格上的 tableview 计算的高度错误.

如果我滚动回顶部,一切都很好,因为所有图像都已在缓存中。

每个人都是怎么做到的? facebook 或 instagram 如何做到这一点?从任何 API 获取单元格高度后如何更新?

【问题讨论】:

  • 您能找到更好的解决方案吗?这让我很头疼???? .

标签: ios swift uitableview


【解决方案1】:

您是否尝试将以下内容添加到您的 viewDidLoad:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140

那么无论您在哪里填充其他元素,您当然也需要调整这些元素的约束和高度。

我建议对单元格进行子分类,并为要为其填充数据的单元格创建一个 set 方法。这样,您可以调整单元格中元素的约束,以更好地处理填充它的数据。

【讨论】:

    【解决方案2】:

    我实际上做了以下工作:

    if (self.firstLoaded[indexPath.row] == false) {
                                self.firstLoaded[indexPath.row] = true
                                DispatchQueue.main.async {
                                    self.tableViewController.tableView.reloadData()
                                }
    }
    

    firstLoaded 只是告诉表格该行已经从 URL 接收到图像并计算/存储了正确的高度。

    另外,我用过这个:

    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            cellHeights[indexPath] = cell.frame.size.height
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return UITableViewAutomaticDimension
    }
    
    override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
            if let height = cellHeights[indexPath] {
                return height
            }
            return 1500
    }
    

    我知道调用 reloadData() 不是一个好习惯,但它解决了我的问题。如果有人有其他建议,请随时分享。

    谢谢!

    【讨论】:

    • 您能找到比重新加载数据更好的方法吗?在网上搜索了几个小时,仍然没有找到一些非常好的。