Updating cell height after image downloads

Nitish

I am displaying some text and images in a UITableView. The image first gets downloaded. Since before the image gets downloaded, I don't know the size of image, so I initially put a UIImageView of some fixed size. And when the image is downloaded, I resize the UIImageView.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// Download image

    dispatch_async(dispatch_get_main_queue(), ^{

    // UIImageView resizing  
    });  
});

All this happens in cellForRowAtIndexPath.
The issues I am facing here are :
1. How do I update the height of cell ? Considering that there can be many images in a single cell. So I need to change the position of bottom image when above one downloads.
2. I tried using UITableView beginUpdates and endUpdates, but that scrolls to the top of cell giving a poor user experience.

This is how the UI looks like on reloadData. There are 5 images to be downloaded : UI experience after UITableView reloadData

SwiftArchitect

Short Answer

  • Give enough breathing space to estimatedRowHeight
  • Changing a UITableViewCell once returned by dequeueReusableCellWithIdentifier will not work with cached cells
  • Trigger a single cell reload with reloadRowsAtIndexPaths
  • Manage your cache with Core Data and let NSFetchedResultsController boilerplate code can do all the UI work.

In Details

No unexpected scroll, only updates images as they come:

  1. If the cell being refreshed is at or below the horizon, the UITableView will not scroll
  2. if the cell being refreshed is above the top, the UITableView will not scroll
  3. the UITableView will only scroll when the cell is in plain sight, and requires more space than available.

Let UITableViewAutomaticDimension do the hard work

You need to tell Cocoa Touch that the cell is stale, so that it will trigger a new dequeueReusableCellWithIdentifier, to which you are going to return a cell with the proper height.
Short of reloading the entire table view or one of its section, and assuming that your indexes are stable, invoke -tableView:reloadRows:at:with: passing the indexPath of the cell that just changed, and a .fade animation.

Code:

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.estimatedRowHeight = 250 // match your tallest cell
    tableView.rowHeight = UITableViewAutomaticDimension
}

Use URLSession. When an image becomes available, fire reloadRows:at:with:

func loadImage(_ url: URL, indexPath: IndexPath) {
    let downloadTask:URLSessionDownloadTask =
        URLSession.shared.downloadTask(with: url, completionHandler: {
        (location: URL?, response: URLResponse?, error: Error?) -> Void in
        if let location = location {
            if let data:Data = try? Data(contentsOf: location) {
                if let image:UIImage = UIImage(data: data) {
                    self.cachedImages[indexPath.row] = image // Save into the cache
                    DispatchQueue.main.async(execute: { () -> Void in
                        self.tableView.beginUpdates()
                        self.tableView.reloadRows(
                            at: [indexPath],
                            with: .fade)
                        self.tableView.endUpdates()
                    })
                }
            }
        }
    })
    downloadTask.resume()
}

Once in the cache, cellForRow merely reads into it from the UI thread:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCell(withIdentifier: "id") as! CustomCell
    cell.imageView.image = cachedImages[indexPath.row]      // Read from the cache
    return cell
}

Example: fetch a random set of images from *Wikipedia*

Xcode demo

► Find this solution on GitHub and additional details on Swift Recipes.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

If no Image, change row cell height

From Dev

If no Image, change row cell height

From Dev

Cell height equal to image width

From Dev

UICollectionview set cell height based on image height

From Dev

reloading UItableViewCell after thumbnail image downloads

From Dev

reloading UItableViewCell after thumbnail image downloads

From Dev

Image height after load()

From Dev

Image height after load()

From Dev

Adjust cell height to image cell height within WPF DataGrid

From Dev

My frame height is not updating after changes made

From Dev

WPF DataGrid updating cell style after editing

From Dev

Updating a cell value after each ajax success

From Dev

Cell Row Height based on Image size

From Dev

Calculate Cell height on basis of label text + image

From Dev

Why image not fit to table cell height in html?

From Dev

Image causing table cell height to extend

From Dev

Auto height cell after add text

From Dev

Auto height cell after add text

From Dev

Dynamically updating cell height without having to scroll Swift

From Dev

Handsontable: Rerender a cell after updating the cell's meta?

From Dev

How to resize CollectionView cell height according to image in cell in swift?

From Dev

Cell after scroll show image over image

From Dev

Django correctly delete image after updating file

From Dev

QML Image not updating after source change

From Dev

Image not saving after updating pixel color in PIL

From Dev

How to delete old image after updating in laravel?

From Dev

How to delete old image after updating in laravel?

From Dev

QML Image not updating after source change

From Dev

Layout height not updating properly after collapse and expand animation

Related Related

HotTag

Archive