具有异步 UIImageView 的自动布局 UITableViewCell 不起作用

Posted

技术标签:

【中文标题】具有异步 UIImageView 的自动布局 UITableViewCell 不起作用【英文标题】:Autolayout UITableViewCell with async UIImageView not working 【发布时间】:2019-09-04 20:33:47 【问题描述】:

我有一个UITableView,配置非常基本。 tableview 单元格只包含一个UIImageView

查看层次结构:

我想在UIImageView 中呈现不同尺寸的图像。 UIImageView 的宽度需要固定为可变高度。

Auto Layout 应该可以自动调整单元格的大小,但是在异步下载图像时不起作用。

这是我的cellForRowAt indexPath

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! Cell

    let item = array[indexPath.row]
    let url = URL.init(string: item["imageUrl"] as! String)!

    cell.myImage.image = nil
    DispatchQueue.global().async 
        let data = try! Data.init(contentsOf: url)
        DispatchQueue.main.async 

            let image = UIImage.init(data: data)!
            if let cell = tableView.cellForRow(at: indexPath) as? Cell, cell.myImage.image == nil 

                let multiplier = cell.myImage.bounds.width / image.size.width
                cell.heightConstraint.constant =  multiplier * image.size.height

                cell.myImage.image = image

                cell.layoutIfNeeded()
            
        
    

    return cell

我在 GitHub 上有一个示例项目设置来演示该问题。 https://github.com/RishabhTayal/AutoTableViewPOC

【问题讨论】:

【参考方案1】:

看了你的代码,你想通过自适应单元格高度来调整图片高度

self.tableView.rowHeight = UITableView.automaticDimension
self.tableView.estimatedRowHeight = 1000

图像约束:

Trailing Space to: SuperView
Leading Space to: SuperView
Bottom Space to: SuperView
Top Space to: SuperView
Height Equals:199.5

日志打印会显示太多警告

请注意,func heightForRow 总是先执行,然后再执行 func cellForRowAt

如果你在func cellForRowAt请求图片,你应该在得到高度后再次刷新单元格。我还将删除一个垂直约束,Bottom Space to: SuperView

我下载了Kingfisher,并使用了一个属性来保存下载的图片。

var urlImages = [String : UIImage]()

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! Cell

        let item = array[indexPath.row]
        let urlString = item["imageUrl"] as! String
        let url = URL.init(string: urlString)!

        if let cacheImage = urlImages[urlString] 
            cell.myImage.image = cacheImage
            let height = self.view.bounds.size.width * (cacheImage.size.height / cacheImage.size.width)
            cell.imageHeightConstraint.constant = height
        else
            cell.myImage.kf.setImage(with: url, placeholder: nil, options: .none, progressBlock: nil)  result in

                switch result
                case .success(let value):
                    let image = value.image
                    self.urlImages[urlString] = image

                    let height = self.view.bounds.size.width * (image.size.height / image.size.width)
                    cell.imageHeightConstraint.constant = height

                    tableView.reloadData()

                case .failure(let error):
                    print("error \(error)")
                
            
        

        return cell
    

刷新会先执行func heightForRowAt,现在这样

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 

        let item = array[indexPath.row]
        let urlString = item["imageUrl"] as! String
        if let image = urlImages[urlString] 
            let height = self.view.bounds.size.width * (image.size.height / image.size.width)
            return height
        
        return 44
    

估计身高代码也需要去掉

【讨论】:

以上是关于具有异步 UIImageView 的自动布局 UITableViewCell 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

具有自动布局和最大尺寸保持纵横比的 UIImageView

图像为零时具有固定尺寸 UIImageView 的自动布局?

iOS - 以编程方式在具有自动布局的 UITextField 内定位 UIImageView

具有自动布局和设备旋转的 UIScrollView

Swift:在 UITableViewCell 中异步加载图像 - 自动布局问题

UIImageView 在具有不同高度的自定义 UITableViewCell 内自动调整大小