Swift - StackView 和通过以编程方式添加的视图添加约束到堆栈 - 加载后调整单元格高度?

Swift - StackView and Adding Constraints With Programmatically Added Views To Stack - Adjust Cell Hight After Load?

我正在尝试制作一个自定义 tableView 单元格,该单元格具有来自数组图像的 stackView。

我使用了界面生成器并添加了一个水平 stackView: 中心 X Y中心 顶部+12 底部+12

我正在使用循环添加排列子视图,它工作正常。但是图像非常小,尽管它们不应该是由于它们的 CGRect。但是它们正在被 stackView 调整。

我们的想法是保持堆栈居中,同时还使用 top/bottom 调整单元格的高度。

我推断我面临的图像较小的问题是因为 stackView 初始化为空。所以 stackViews 的高度非常小。因为 imageViews 被添加到其中,所以它们会被调整大小以适应。

怎样才能让一个cell/stackView在显示后调整高度?

注意:我在尝试以编程方式向 imageView 添加顶部和底部约束时也遇到了问题。

for pictogram in pictograms {
            let imageView = UIImageView()
            
            let size = self.bounds.width / CGFloat(pictograms.count + 1)
            print("size: ", size)
            
            imageView.frame = CGRect(x: 0, y: 0, width: size, height: size)
            imageView.contentMode = .scaleAspectFit
            
            imageView.image = pictogram.image
            pictogramStack.addArrangedSubview(imageView)
        }

您使用 UIStackView 的方式有误。堆栈视图将为您安排子视图 - 无需计算宽度和设置框架。

像这样布局你的单元格原型:

请注意底部约束有 Priority: 999。 Auto-layout 需要多次“通过”来布置堆栈视图(特别是在 table 视图单元格中)。对底部约束使用优先级 999 将避免约束冲突错误/警告消息。

像这样设置堆栈视图属性:

使用 Distribution: Fill Equally 我们不需要做任何 let size = self.bounds.width / CGFloat(pictograms.count + 1) 类型的计算。

此外,为了使 design-time 更容易一些,给堆栈视图一个 Placeholder 固有高度:

在 run-time 时 没有 效果,但可以让您在设计时清楚地看到您的单元格元素。

现在,当您用图像视图“填充”堆栈视图时,没有 .frame = 设置,您需要添加的唯一约束是高度 == 宽度:

NSLayoutConstraint.activate([
    // image view should have 1:1 ratio
    imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor),
])

这是一个完整的例子:

class HorizontalImagesStackCell: UITableViewCell {
    
    @IBOutlet var theStack: UIStackView!
    
    func addImages(_ pictograms: [String]) -> Void {
        
        // cells are reused, so remove any previously added image views
        theStack.arrangedSubviews.forEach {
            [=11=].removeFromSuperview()
        }
        
        pictograms.forEach { s in
            // make sure we can load the image
            if let img = UIImage(named: s) {
                // instantiate an image view
                let imageView = UIImageView()
                // give it a background color so we can see its frame
                imageView.backgroundColor = .green
                // scale aspect fit
                imageView.contentMode = .scaleAspectFit
                // set the image
                imageView.image = img
                NSLayoutConstraint.activate([
                    // image view should have 1:1 ratio
                    imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor),
                ])
                // add it to the stack
                theStack.addArrangedSubview(imageView)
            }
        }
        
    }
}

class ImagesInStackTableViewController: UITableViewController {
    
    // we'll display 5 rows of images
    //  going from 5 images to 4 images ... to 1 image
    let myData: [Int] = [5, 4, 3, 2, 1]
    
    let myImages: [String] = [
        "img1", "img2", "img3", "img4", "img5"
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myData.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "HCell", for: indexPath) as! HorizontalImagesStackCell

        // get the first n number of images
        let a: [String] = Array(myImages.prefix(myData[indexPath.row]))
        
        cell.addImages(a)
        
        return cell
    }
}

使用这 5 张图片:

我们得到了这个结果(图像视图设置为 .scaleAspectFit 并且有绿色背景所以我们可以看到框架):