下载图像和高度限制快速更改后,如何更新tableview单元格的高度?

时间:2018-09-13 09:58:13

标签: ios swift uitableview

在更新异步下载的图像的图像高度约束后,如何更新tableview单元格的高度?

下载图像和更改约束后如何触发tableView单元重新布局?

执行此操作的最佳方法是什么?

已经尝试将代码放入Dispatch主队列中,但是同样会导致不良结果。我正在cellForRow方法中执行此操作,还将其移至willDisplayCell。这个问题一次又一次...

使用Kingfisher库进行图像缓存的代码示例:

    if let imgLink = post.imageLink {
                if let url = URL(string: imgLink) {

                    cell.postImage.kf.setImage(with: url, placeholder: UIImage(), options: nil, progressBlock: nil) { (image, error, cacheType, imageURL) in

                        if let image = image, cell.tag == indexPath.row {
                            cell.heightConstraint.constant = image.size.height * cell.frame.size.width / image.size.width   
                        }
                    }
                }
    }

4 个答案:

答案 0 :(得分:2)

您可以尝试调用这两行,以使在图像可用后重新计算像元高度:

tableView.beginUpdates()
tableView.endUpdates()

请参见文档https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates:“还可以在不重新加载单元格的情况下,使用此方法以及endUpdates()方法来设置行高变化的动画。”

答案 1 :(得分:1)

我有同样的问题。您需要记住的是Tableview重用单元格,并且正在加载图像异步。

推荐:您可以做的是请反手团队提供图像的高度和宽度,以便您可以计算像元高度并尽快返回。

如果无法执行此操作,则可以在数据源中保留下载图像的大小。因此,在下载图像之前,请检查数据源中的图像大小并更新高度约束常数。

另一件事是,您应该在cellForRow和willDisplay单元格中都这样做(我知道这不是一个好习惯,但要满足tableview自动尺寸)

更新高度常数后,您应该使用这对代码重新加载单元格。

    cell.setNeedsLayout()
    cell.layoutIfNeeded()

我怎么做

 if let imagesize = post.imageSize { 
      cell.updateHeightPerRatio(with: imagesize)

 } else {
      // Here load size from URL  and update your datasource 

  } 
  // Load image from URL with any SDWebimage or any other library you used

答案 2 :(得分:1)

恕我直言,因为 ppalancica pointed out 调用 beginUpdates 和 endUpdates 是理想的方式。您不能从 UITableViewCell 内部引用 tableView,正确的方法是使用委托并从实现委托的 ViewController 调用 beginUpdates 和 endUpdates。

委托:

protocol ImageCellDelegate {
    func onLayoutChangeNeeded()
}

UITableViewCell 实现:

class ImageCell: UITableViewCell {
    var imageView: UIImageView = ...
    var delegate: ImageCellDelegate?
    ...

    func setImage(image: UIImage) {
        imageView.image = image
        //calling delegate implemented in 'ViewController'
        delegate?.onLayoutChangeNeeded()
    }

    ...
}

视图控制器实现:

class ViewController: UIViewController, UITableViewDataSource, ImageCellDelegate {
    var tableView: UITableView = ...
    .....
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let imageCell = tableView.dequeueReusableCell(withIdentifier: id, for: indexPath) as! ImageCell
        //setting 'delegate' here
        imageCell.delegate = self
        return imageCell
    }
    
    //called from 'ImageCell' when 'image' is set inside 'setImage'
    func onLayoutChangeNeeded() {
        tableView.beginUpdates()
        tableView.endUpdates()
    }

    .....
}

答案 3 :(得分:0)

以下是我实际做过的事情:

e.clientX

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

我也使用了这个

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

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

谢谢!