簡體   English   中英

圖像下載和高度約束迅速改變后如何更新tableview單元格高度?

[英]How to update tableview cell height after image downloaded and height constraint changed swift?

更新異步下載圖像的圖像高度約束后如何更新tableview單元格高度?

圖像下載和約束更改后如何觸發tableView單元格重新布局?

這樣做的最佳方法是什么?

已經嘗試將代碼放入 Dispatch 主隊列,但結果同樣糟糕。 我在 cellForRow 方法中這樣做,也將它移動到 willDisplayCell。 一次又一次這個問題...

使用 Kingfisher 庫進行圖像緩存的代碼示例:

    if let imgLink = post.imageLink {
                if let url = URL(string: imgLink) {

                    cell.postImage.kf.setImage(with: url, placeholder: UIImage(), options: nil, progressBlock: nil) { (image, error, cacheType, imageURL) in

                        if let image = image, cell.tag == indexPath.row {
                            cell.heightConstraint.constant = image.size.height * cell.frame.size.width / image.size.width   
                        }
                    }
                }
    }

您可以嘗試調用這 2 行以在圖像可用后重新計算單元格高度:

tableView.beginUpdates()
tableView.endUpdates()

請參閱文檔https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates :“您還可以使用此方法后跟 endUpdates() 方法來為行高的變化設置動畫,而無需重新加載單元格.”

恕我直言,正如ppalancica 指出的那樣,調用 beginUpdates 和 endUpdates 是理想的方式。 您不能從 UITableViewCell 內部引用 tableView,正確的方法是使用委托並從實現委托的 ViewController 調用 beginUpdates 和 endUpdates。

代表:

protocol ImageCellDelegate {
    func onLayoutChangeNeeded()
}

UITableViewCell 實現:

class ImageCell: UITableViewCell {
    var imageView: UIImageView = ...
    var delegate: ImageCellDelegate?
    ...

    func setImage(image: UIImage) {
        imageView.image = image
        //calling delegate implemented in 'ViewController'
        delegate?.onLayoutChangeNeeded()
    }

    ...
}

視圖控制器實現:

class ViewController: UIViewController, UITableViewDataSource, ImageCellDelegate {
    var tableView: UITableView = ...
    .....
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let imageCell = tableView.dequeueReusableCell(withIdentifier: id, for: indexPath) as! ImageCell
        //setting 'delegate' here
        imageCell.delegate = self
        return imageCell
    }
    
    //called from 'ImageCell' when 'image' is set inside 'setImage'
    func onLayoutChangeNeeded() {
        tableView.beginUpdates()
        tableView.endUpdates()
    }

    .....
}

我有同樣的問題。 您需要記住的是 Tableview 重用單元格並且您正在異步加載圖像。

推薦:您可以要求您的反手團隊為您提供圖像的高度和寬度,以便您計算單元格高度並盡快返回。

如果您不能這樣做,您可以在數據源中保留下載圖像的大小。 因此,在下載圖像之前,請檢查數據源的圖像大小並更新高度約束常量。

另一件事是你應該在 cellForRow 和 willDisplay 單元格中都這樣做(我知道這不是一個好習慣,但要滿足 tableview 自動維度)

更新高度常量后,您應該使用這對代碼重新加載您的單元格。

    cell.setNeedsLayout()
    cell.layoutIfNeeded()

我是怎么做的

 if let imagesize = post.imageSize { 
      cell.updateHeightPerRatio(with: imagesize)

 } else {
      // Here load size from URL  and update your datasource 

  } 
  // Load image from URL with any SDWebimage or any other library you used

我實際所做和以某種方式工作的內容如下:

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

firstLoaded 只是告訴表這一行已經從 URL 接收到圖像並計算/存儲了正確的高度。

另外,我使用了這個:

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
}

我知道調用 reloadData() 不是一個好習慣,但它解決了我的問題。 如果有人有其他建議,請不要猶豫,分享。

謝謝!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM