如何为具有 0 到 2 个图像的 UITableViewCells 设置可调整高度的约束?

How to set constraints for resizable heights on UITableViewCells that have between 0 and 2 images?

问题解释后的代码。

我有一个 UIViewController 包含一个 UITableView,其中 UITableViewCell 显示一个、两个或零个图像。对于一张和两张图像,单元格的高度始终为 72,但如果没有任何图像,它需要为零。我的 table 单元格中有两个 UIView,第一个包含一个 UIImageView,第二个包含两个。我是隐藏还是显示相关的,具体取决于该单元格是否有一张或两张图像。如果单元格有零个图像,两个 UIView 都被隐藏,但当然它们仍然构成约束设置的一部分,因此生成的单元格仍然是 72 像素高,而我需要它折叠。

有人告诉我, 创建高度可调整大小 UITableViewCell 的方法是通过在情节提要中设置约束,并且乱用值以编程方式即时约束的约束将导致布局问题。我不知道这些建议是否属实,所以我尝试了以下方法(但没有成功):

  1. 在我的 ResizableImageCell 调用中设置对我的 UIView 控制高度的 NSLayoutConstraint 的显式引用,这会导致 Unable to simultaneously satisfy constraints 错误;和

  2. 在我的 ResizableImageCell 调用中设置对 all NSLayoutConstraint 控制高度的显式引用; and/or

  3. 添加和删除 UIView,在您开始滚动浏览 table 之前两者都可以正常工作,于是 table 开始上下跳动将手指从屏幕上移开后。

这是控制 ViewController:

的当前代码
import UIKit

class ViewController: UIViewController
{
    @IBOutlet weak var tableView: UITableView!

    let imageNames = [ "room", "street", "tree" ]



    override func viewDidLoad ()
    {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 44.0
    }



    func getRandomInt ( from start: Int, to end: Int ) -> Int
    {
        return Int( arc4random_uniform( UInt32( ( end + 1 ) - start ) ) ) + start
    }
}



extension ViewController: UITableViewDataSource
{
    @available( iOS 2.0, * )
    public func tableView ( _ tableView: UITableView, cellForRowAt indexPath: IndexPath ) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell( withIdentifier: "ResizableImageCell" ) as! ResizableImageCell
        let numImages = getRandomInt( from: 0, to: 2 )

        cell.view1.isHidden = numImages != 1
        cell.view2.isHidden = numImages != 2

        var rand = getRandomInt( from: 0, to: imageNames.count - 1 )

        switch numImages
        {
        case 1:     cell.image1.image = UIImage( named: imageNames[ rand ] )
        case 2:     cell.image2.image = UIImage( named: imageNames[ rand ] )
        default:    ()
        }

        guard numImages == 2 else { return cell }

        rand = getRandomInt( from: 0, to: imageNames.count - 1 )

        cell.image3.image = UIImage( named: imageNames[ rand ] )

        return cell
    }



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

这是控制我的定制 ResizableImageCell 单元格的当前代码

import UIKit

class ResizableImageCell: UITableViewCell
{
    @IBOutlet weak var view1: UIView!
    @IBOutlet weak var view2: UIView!

    @IBOutlet weak var image1: UIImageView!
    @IBOutlet weak var image2: UIImageView!
    @IBOutlet weak var image3: UIImageView!



    override func awakeFromNib ()
    {
        super.awakeFromNib()
    }
}

这是现有故事板的屏幕截图:

感谢您的阅读。

我在我的项目中使用 heighForRow 函数解决了这个问题。

在ViewController中:

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

    //Check if you have to display images or not

    //return 75 or CGFloat.ulpOfOne 
}

也许使用此解决方案,您必须在 cellForRowAtIndexPath 函数之前创建 let numImages = getRandomInt( from: 0, to: 2 ) 并将 64 个结果存储在数组中。

编辑: 来自 Josh Homann 的重要说明:

Do not return 0 for the height or you may get some auto layout errors in the console because your rect is degenerate. return CGFloat.ulpOfOne which is infinitesimally small but still non zero.

在使用@Chief-Lutz 的 heightForRowAt 建议(在上文中概述)解决了这个问题后,我随后意识到还有另一种同样有效的解决方案。代替 heightForRowAt 内的 运行 高度计算,可以有多个笔尖,每个笔尖旨在处理不同数量的图像。这样做的好处是高度计算发生在引擎盖下,使您的代码更简单、更短;而缺点是有多个笔尖,其中可能有一些重复的布局 and/or 约束。

如果您的单元格包含一个或多个零线 UILabel,这种方法将特别有用,因为在这种情况下 heightForRowAt 中需要的部分计算涉及 [re]创建单元格 UILabel 并用文本填充它们,以便它们可以调整大小并告诉您渲染时每个单元格在单元格中的高度(heightForRowAt 称为 之前 cellForRowAt).