给定内部 UIImageView 的固有大小,如何使用约束更新单元格的高度?

How to update the height of a cell given the intrinsic size of an UIImageView inside using constraints?

经过很长的时间我得出了这个结论:不可能做到。

现在,我不想相信。这是我想做的:使用约束以使布局自动进行,这样如果 UIImageViewimage 被替换,布局自动调整。

    // This works, the cell height is adjusted to the height of this image
    cell.myImageView.image = UIImage(named:"myDefaultImage") 

    // This doesn't work.
    // The result is that the size of both the image and the cell are still the same size and only the image changes
    // The result I expect is that the cell layout is recalculated and the size changes alongside the image itself
    // I repeat, right now the image content changes, it displays the new image but no re layout is happening. Intrinsic content size of the image changes, but it is not propagated to the UI.
// Putting reload cell code here will make the cell reload indefinitely, I don't want to add more state to keep track of that
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
      cell.myImage.image = UIImage(named:"downloadedFromTheInternetImage")
    }

这意味着:

原因是,autolayout 应该是 automatic。也因为这适用于其他情况,例如 UILabel,其中,文本的增加会使布局发生变化。

如果你还坚持只建议手动,请不要,我已经知道手动可以了。事实上,任何事情都可以用数学来完成......我什至不需要 table 视图。

如果这做不到,那好吧,但我觉得这应该是可能的。我把完整的代码留在下面...

我愿意使用:(我已经尝试了这些的所有组合,但没有结果)

完整代码:

import UIKit

// The view controller with a simple table
class RootViewController2: UIViewController {
    var once = false
    let table = UITableView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.brown
        
        table.dataSource = self
        table.backgroundColor = .green
        
        table.estimatedRowHeight = 122.0
        table.rowHeight = UITableView.automaticDimension
        
        table.register(MyCell2.self, forCellReuseIdentifier: "reusedCell")
        self.view.addSubview(table)
    }
    
    
    override func viewDidLayoutSubviews() {
        table.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
    }
}

// The table data configuration, just 100 cells of the same image, they change into a new image after 1 second of being displayed
extension RootViewController2: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = table.dequeueReusableCell(withIdentifier: "reusedCell", for: indexPath) as! MyCell2
        cell.imageView2.image = UIImage(named: "Group") // This image is short
        
        // Imagine this is a newtwork request that returns later
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            cell.imageView2.image = UIImage(named: "keyboard") // This image is large, the cell should expand
        }
        
        return cell

    }
    
}

class MyCell2: UITableViewCell {
    
    let imageView2 = UIImageView()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.contentView.addSubview(imageView2)

        // Constraints such that the intrinsic size of the image is used
        // This works correctly, the problem is, if the image is changed, the layout is not
        imageView2.translatesAutoresizingMaskIntoConstraints = false
        imageView2.topAnchor.constraint(equalTo: self.contentView.topAnchor).isActive = true
        imageView2.leftAnchor.constraint(equalTo: self.contentView.leftAnchor).isActive = true
        let bottom = imageView2.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: 10)
        bottom.priority = UILayoutPriority(900)
        bottom.isActive = true
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

我相信您知道这是不是更新单元格内容的方式:

    // Imagine this is a newtwork request that returns later
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        cell.imageView2.image = UIImage(named: "Keyboard") // This image is large, the cell should expand
    }

但是,它确实说明了问题。

所以,问题是单元格布局 IS 改变了,但这并没有改变 tableView布局。

任何时候您的单元格内容发生变化 - 例如像您的示例代码一样设置图像,更改多行标签的 .text 等 - 您必须 通知table 视图:

    // Imagine this is a newtwork request that returns later
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        cell.imageView2.image = UIImage(named: "Keyboard") // This image is large, the cell should expand
        
        // add this line
        tableView.performBatchUpdates(nil, completion: nil)
    }