skip to Main Content

How do I update cell height after image downloaded from server using Kingfisher setImage with completion handler method? After the image downloads, I resize its height constraint using this: cell.imageHeight.constant = image.size.height * cell.frame.size.width / image.size.width.

The image is downloaded and set on cellForRow method, but I tried also in willDisplayCell, same problems. I also check cell.tag == indexPath.row in completion handler of setImage method.

I’ve already tried the following methods and none worked:

  • heightForRow is UITableViewAutomaticDimension and estimatedHeightForRowAt is some value (biggest possible cell) and all other combinations of these 2
  • tableview begin/end updates
  • reloadRows at indexPath
  • cell.setNeedsLayout, layoutIfNeeded or layoutSubviews
  • dispatch main async

Either of them come to the same issues: jumpy table on scrolling, cell height wrong on first display and to update it I have to scroll up and down to hide and show that cell, wrong height calculated by the tableview on some cells.

If i scroll back to top, everything is alright because all images are already in cache.

How does everybody do this? How does facebook or instagram do this? How to update cell height after you get it from any API?

2

Answers


  1. Chosen as BEST ANSWER

    What I actually did and worked somehow is the following:

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

    firstLoaded just tells the table that this row has already received image from URL and calculated / stored correct height.

    Also, I used this:

    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            cellHeights[indexPath] = cell.frame.size.height
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return UITableViewAutomaticDimension
    }
    
    override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
            if let height = cellHeights[indexPath] {
                return height
            }
            return 1500
    }
    

    I know that calling reloadData() is not a good practice, but it solved my problem. If anybody has some other advices, please do not hesitate to share it.

    Thanks!


  2. Have you tried adding the following to your viewDidLoad:

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 140
    

    then wherever you are populating the other elements you will of course need to adjust the constraint(s) and height for those as well.

    I would recommend sub-classing the cell and create a set method for the cell where the data is being populated for it. this way you can adjust the constraints for the elements in the cell to better work with the data populating it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search