简体   繁体   English

异步下载图像后表格单元格框架未更新

[英]Table cell frame not updated after Image downloaded asynchronously

I have a UITableViewCell with UITableViewAutomaticDimension which consists of Image and title.我有一个带有 UITableViewAutomaticDimension 的 UITableViewCell,它由图像和标题组成。 After I get the data from API, I reload tableView, but only title in UILabel appears and not the image, as in below image从API获取数据后,我重新加载tableView,但只显示UILabel中的标题而不显示图像,如下图重新加载之后和滚动之前

After i scroll the tableView, the images appear and are adjusted according to there size.在我滚动 tableView 后,图像出现并根据那里的大小进行调整。 Like Below喜欢下面滚动后

I want this to happen before scrolling.我希望在滚动之前发生这种情况。

Things I have tried already我已经尝试过的事情

  1. Using a placeholder image, but it results to downloaded image to take placeholder image size and after scrolling the cell size is updated correctly.使用占位符图像,但会导致下载的图像采用占位符图像大小,并且在滚动后单元格大小会正确更新。
  2. Using layout if needed or setNeedLayout如果需要,使用布局或 setNeedLayout
  3. Waiting for the file to download and then return cell after calculating the size, but this result in lagging the tableview while scrolling等待文件下载,然后在计算大小后返回单元格,但这会导致滚动时 tableview 滞后

My cellForRowAt Code我的 cellForRowAt 代码

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.custom.rawValue) as? CustomCell else {return UITableViewCell()}
    cell.update(model: arrImages[indexPath.row])
    return cell
}

My Cell Class Logic我的单元格类逻辑

Update Method更新方法

func update(model: ImageModel) {
    self.presentModel = model
}

UI Changes in cell单元格中的 UI 更改

    var presentModel: ImageModel? {
    didSet{
        if let url = presentModel?.imgURL {
            imgView.kf.indicatorType = .activity
            imgView.kf.setImage(with: url)
        }
        lblTitle.text = presentModel?.title
    }
}

Addition info I am using KingFisher third party to download images.附加信息我正在使用 KingFisher 第三方下载图像。

You should reload your table view once image is loaded from the url. 从网址加载图片后,您应该重新加载表格视图。

You might have multiple cells with image on each cell. 您可能有多个单元格,每个单元格上都有图像。 So you should call the tableView's reload method once your image is downloaded from the url asynchronously. 因此,一旦从url中异步下载了图片,就应该调用tableView的reload方法。

You said that images are appears properly when you scroll down the cells off and on screens, because the tableView's func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) will be called when cell is about to visible on screen. 您说过,当您向下或向下滚动屏幕上的单元格时,图像会正确显示,因为当单元格即将在屏幕上可见时,将调用tableView的func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)。

So you should call tableView.reloadData() or tableView.reloadRows(at: [imageLoadedCellIndexPath], with: .automatic) method to trigger the tableview's delegate and data source methods. 因此,您应该调用tableView.reloadData()tableView.reloadRows(at: [imageLoadedCellIndexPath], with: .automatic)方法来触发tableview的委托和数据源方法。

As you are using Kingfisher extensions to download images from url, you can try using the below method to know the download status. 当您使用Kingfisher扩展程序从url下载图像时,可以尝试使用以下方法来了解下载状态。

imageView.kf.setImage(with: url, completionHandler: { 
    (image, error, cacheType, imageUrl) in

})

instead of imageView.kf.setImage(with: url). 而不是imageView.kf.setImage(with: url).

Example: 例:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.custom.rawValue) as? CustomCell else {return UITableViewCell()}

    cell.update(model: arrImages[indexPath.row])

    let imageModel = arrImages[indexPath.row]

    if let url = imageModel?.imgURL {

//Check if image is already downloaded
        ImageCache.default.retrieveImage(forKey: url.absoluteString, options: nil) {
            image, cacheType in

//Image is already downloaded
            if let image = image {

                //cell.imgView.image = image
                imgView.kf.setImage(with: url) //try this line instead of above one

            } else { //Download
                imgView.kf.indicatorType = .activity
                cell.imgView.kf.setImage(with: url, completionHandler: {
                    (image, error, cacheType, imageUrl) in

                    if image != nil{

                        tableView.reloadRows(at: [indexPath], with: .automatic)

                        //OR

                        tableView.reloadData()
                    }
                })
            }
        }

    }

    return cell
}

And Comment image download code in cell as like below, 并在单元格中添加注释图像下载代码,如下所示,

var presentModel: ImageModel? {
    didSet{
//            if let url = presentModel?.imgURL {
//                imgView.kf.indicatorType = .activity
//                imgView.kf.setImage(with: url)
//            }
              lblTitle.text = presentModel?.title
        }
    }

Do following做以下

  • Add a stack view inside you table cell在表格单元格内添加堆栈视图

  • Add add height constraint to the stack view向堆栈视图添加添加高度约束

  • Create IBOutale of this height constraint创建此高度约束的 IBOutale

  • load image with the URL using kingfisher SDK with completion block.使用带完成块的 kingfisher SDK 加载带有 URL 的图像。

  • Inside completion block calculate the height you want to set to your image view内部完成块计算要设置为图像视图的高度

  • Create UIImageView with frame using the calculated height and width.使用计算的高度和宽度创建带有框架的 UIImageView。

  • Add ImageView as arrangedsubView in your stack view在您的堆栈视图中添加 ImageView 作为排列子视图

  • set the constant value of constrain to your calculated height将约束的常量值设置为您计算出的高度

  • add these two lines after adding ImageView to stack view将 ImageView 添加到堆栈视图后添加这两行

    stackView.setNeedsLayout() stackView.layoutIfNeeded() sample code stackView.setNeedsLayout() stackView.layoutIfNeeded() 示例代码

let imageSize = image.size
            let width = UIScreen.main.bounds.width - 20
            let height = (width * imageSize.height) /  imageSize.width
            let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
            imageView.image = image
            heightConstraint.constant = height
            stackView.addArrangedSubview(imageView)
            stackView.setNeedsLayout()
            stackView.layoutIfNeeded()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 异步下载图像时,“集合”视图单元格中的图像未更新 - Image in Collection view cell is not updated when the image is downloaded asynchronously 下载映像后调整表格单元格大小 - Resize table cell after image downloaded 异步更新表单元格图像 - Update table cell image asynchronously 下载图像后重新加载CollectionView的单元格 - Reload cell of CollectionView after image is downloaded 使用AFNetworking异步下载图像后,是否可以从UIImageView获取图像 - Is it possible to get Image from UIImageView after image is downloaded asynchronously using AFNetworking 根据下载的图像高度调整表格单元格的高度 - Resize the Table cell height as per downloaded image height 表格视图单元格中的图像视图框架 - image view frame in cell of a table view 异步下载图像并确定下载了哪个图像? - Download images asynchronously and identify which image has downloaded? Swift - 如何根据异步下载的数据创建表视图? - Swift - How to create a table view based on data downloaded asynchronously? 异步下载的图像仅在点击或滚动后出现在UITableView中 - Images downloaded asynchronously only appear in UITableView after tap or scroll
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM