0

I am trying to download image from server and want to load images inside my cell but as i am downloading inside cellForRowAt method it wont get height for the first time. If i scroll up and scroll down again the image will have proper height.

Using Kingfisher to download images from server

var homeList = [NSDictionary]()
var rowHeights : [Int:CGFloat] = [:]

func numberOfSections(in tableView: UITableView) -> Int 
{
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return homeList.count
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return 100
}

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

        if let height = self.rowHeights[indexPath.row]{
            print(" Height \(height)")
            return height
        }
        else{
            return 160
        }
}


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


    if let homeObject = homeList[safe: indexPath.row] {
        if let dynamicURL =  homeObject["dynamic_card_url"] as? String, dynamicURL != "" {

            tableView.register(UINib(nibName: "DynamicCell", bundle: nil), forCellReuseIdentifier: "\(indexPath.row)")
            let cell = tableView.dequeueReusableCell(withIdentifier: "\(indexPath.row)", for: indexPath) as! DynamicCell

            KingfisherManager.shared.downloader.downloadImage(with: URL(string: dynamicURL)!, options: .none, progressBlock: nil, completionHandler: { (image, error, url, data) in
                DispatchQueue.main.async {

                    if (image != nil || url != nil){
                    let aspectRatio = (image! as UIImage).size.height/(image! as UIImage).size.width
                    cell.dynamicImageView.image = image
                    let imageHeight = self.view.frame.width*aspectRatio
                    self.rowHeights[indexPath.row] = imageHeight
                    }else{
                        print("Image or URL is nil")
                    }
                }
            })
            cell.selectionStyle = .none
            cell.backgroundColor = UIColor.clear
            return cell       
    }
}
}
Srini V
  • 11,045
  • 14
  • 66
  • 89
Abhijit Hadkar
  • 210
  • 2
  • 11

2 Answers2

0

When you downloaded your image you should reload your cell to change it size to appropriate one. You get right sizes as you scrolling because tableView calls heightForRowAt when it needs to display new cell. So inside in DispatchQueue.main.async { reload the cell after setting all necessary properties UITableView().reloadRows(at: [IndexPath], with: UITableViewRowAnimation.automatic)

Mikhail Maslo
  • 616
  • 6
  • 13
  • and what will be the height in heightForRowAt at else part @Михаил Масло – Abhijit Hadkar Nov 04 '17 at 05:39
  • there is no method like tableView.reloadCells(atIndexPaths: [indexPath]) @Михаил Масло – Abhijit Hadkar Nov 04 '17 at 05:49
  • @AbhijitHadkar I updated the answer. About size of the size it will will be default 160 which you already have provided since you didn't load image and doesn't know the size – Mikhail Maslo Nov 04 '17 at 08:22
  • it is reloading the rows but it is so fast updating that my app is crashing. – Abhijit Hadkar Nov 04 '17 at 09:48
  • @AbhijitHadkar Can you be more specific about crashing? What actually caused it? – Mikhail Maslo Nov 04 '17 at 09:50
  • The things is that i am receiving an image is of having random height like at same time img1 is of 160 height and img2 is of height 337 so if i set default size to 160 the img2 looks weird coz it is getting height = 160 if i scroll up and down the image will get its proper size coz in if condition if let height = self.rowHeights[indexPath.row]{ print(" Height \(height)") return height } calculating proper height – Abhijit Hadkar Nov 04 '17 at 09:56
  • @AbhijitHadkar to resize cell - your need to reload it or set authorising `UITableViewAutomaticDimension` for googling. I didn't have that case when I need to reload a lot of cells concurrently. But right now you doing everything in one main thread and thus reloading too and there won't be errors (from my perspective). Again, if you can be more specific about occurred error probably I could be helpful – Mikhail Maslo Nov 04 '17 at 10:12
  • See from server i am downloading images which is having random size like for img1 height=160, img2 height=337 and img3 height=160 and as per my code the default size of those image will be 160 so when imag2 having 337 height is loaded it is not rendering properly when loaded at first time but when i am scroll off that img2 cell and again scroll in that cell that imag2 will be properly loaded because as per cellForRowAt height array is getting filled with heights like [158,337,159]. So for img2 its looks glitchy – Abhijit Hadkar Nov 04 '17 at 10:30
  • Hey Mikhali any suggestions on above? – Abhijit Hadkar Nov 06 '17 at 12:18
  • Got the solution for my own code. I wrote a method which will accept indexPath as a parameter and called this method inside my estimatedRowHeight of tableview as it is called before heightForRowAt so advantage of doing this is that u will have your heightArray ready with proper calculated height and will iterrate this array inside heightForRowAt. So my tableview got proper height even if it is coming from server and with any random height my tableviewCell will render it properly. – Abhijit Hadkar Nov 08 '17 at 06:25
  • this link helps a lot ---> https://stackoverflow.com/questions/44338392/swift-dynamic-uitableviewcell-size-based-on-image-aspect-ratio – Abhijit Hadkar Nov 08 '17 at 06:25
0

I used this guys suggestion: https://stackoverflow.com/a/33499766/8903213

code:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    cell.imageView?.kf.setImage(with: URL(string: urlOfPhoto)!, placeholder: PlaceholderImages.user, completionHandler: {
         (image, error, cacheType, imageUrl) in
         cell.layoutSubviews()
    })
    ...

and this seems to be working for me.

Michael Economy
  • 608
  • 6
  • 21