Tim J
Tim J

Reputation: 1271

UITableView not showing remote image until scroll or reload of tableviewcell

I am using Kingfisher to download and cache remote images.

I would like to render those images in a UITableViewCell

Currently the images do not show until I scroll.

I suspect this is because the initial image size is nil, once I scroll the cell is redrawn and the image is rendered.

To negate this issue I have called tableView.reloadRows(at: [indexPath], with: .none) in the completion handler of Kingfisher

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "FeedTableViewCellId", for: indexPath) as! FeedGifCell

    let url = URL(string: items[indexPath.item])!
    let imageView = ImageResource(downloadURL: url, cacheKey: "\(url)-imageview")
    let placeHolderImage = UIImage.from(hex: "ffffff").resize(width: 1, height: 190)
    cell.gifImage.kf.setImage(with: imageView, placeholder: placeHolderImage) { _ in
        tableView.reloadRows(at: [indexPath], with: .none)
    }

    return cell
}

I have applied a simple placeholder of a fixed height and width to give the cell some height before the image is applied.

I am not sure this is the best approach, I do not like calling tableView.reloadRows(at: [indexPath], with: .none) this feels a little.....hacky.

Also, before the cell is redrawn I have the white space, my placeholder, then a jump as the correct image / size is applied.

Is it possible to simply prevent the cell from being visible at all until the image has been applied?

Upvotes: 1

Views: 1802

Answers (1)

Glenn Posadas
Glenn Posadas

Reputation: 13283

No! You don't have to reload the tableView in any way after the image in a certain cell gets done downloading. Other than that, you're doing everything correctly. I use Kingfisher too.

But in the future, you could just make a function in your cell class, say setupCell(_ imageURL: URL?). Anyways, going on, in your cellForRow method, just do it like this:

cell.gifImage.kf.setImage(with: imageView, placeholder: placeHolderImage, completionHandler: nil)

Now, in case that there's no image downloaded or you have no image URL string to be made to URL object, you could catch it in Kingfisher's error block, then you will need to pass your error image (a UIImage) object to your imageView so that there would be no duplicate image.

For example, I have the following in my cell's setupCell() function:

    if let url = vendor.image?.URLEscaped {
        let resource = ImageResource(downloadURL: url, cacheKey: url.absoluteString)
        self.imageView_Vendor.kf.setImage(with: resource, options: [.transition(.fade(0.2)), .cacheOriginalImage])
        return
    }

    self.imageView_Vendor.image = nil

I hope this helps!

EDIT:

For the handling of image height, this could help: https://stackoverflow.com/a/52787062/3231194

Upvotes: 2

Related Questions