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

Posted

技术标签:

【中文标题】Swift - StackView 和添加约束,以编程方式添加视图到堆栈 - 加载后调整单元格高度?【英文标题】:Swift - StackView and Adding Constraints With Programmatically Added Views To Stack - Adjust Cell Hight After Load? 【发布时间】:2020-06-27 22:00:31 【问题描述】:

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

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

我正在使用循环来添加 Arranged Subview,它工作正常。但是图像非常小,即使它们不应该是由于它们的 CGRect。但是它们正在被 stackView 调整。

这个想法是保持堆栈居中,同时还使用顶部/底部来调整单元格的高度。

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

如何让单元格/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)
        

【问题讨论】:

将 Arranged Subviews 添加到开始为空的堆栈视图中没有问题。您对约束所做的其他事情导致了问题。您需要显示单元原型的图像(确保它显示所有约束),并包含您用于添加排列的子视图的代码。 嘿,唐,将视图添加到堆栈中没有问题。问题是设置单元格的高度。 - 单元格仅包含堆栈视图,其中提到了 4 个约束。 如果你实例化一个UIImageView,给它的.frame一个CGRect,然后将它添加为一个堆栈视图的arrangedSubview,那个CGRect将被忽略。这就是为什么我建议你展示你用来添加排列的子视图的代码。 嘿,唐,我就是这样做的。 - 添加代码。 好的 - 再澄清一点...您是否将 imageViews 添加到 horizo​​ntal 堆栈视图?你想让它们宽度相等吗?你想要高度 = 宽度(1:1 的比例)? 【参考方案1】:

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

像这样布置你的细胞原型:

请注意,底部约束具有Priority: 999。自动布局需要进行多次“通过”来布局堆栈视图(特别是在表格视图单元格中)。为底部约束使用 999 的优先级将避免约束冲突错误/警告消息。

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

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

另外,为了让设计时更容易,给堆栈视图一个 Placeholder 固有高度:

这将在运行时没有影响,但可以让您在设计时清楚地看到您的单元格元素。

现在,当您使用图像视图“填充”堆栈视图时,没有 .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 
            $0.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 并具有绿色背景,因此我们可以看到帧):

【讨论】:

嘿,唐,谢谢你写这篇文章。这是一个很棒的指南。 - 尽管我已经遵循了它,但我仍然无法让单元以大于标准单元高度的大小加载。 (无论高度是否设置为自动。) 更新:你的循环对我不起作用。出于某种原因,它两次添加图像。而且尺寸还是不对。回到我最初使用的循环,删除固有尺寸,并重新设置框架,最后,(底部@999​​ 的主要道具)它的工作! :) 还有 - NSLayoutConstraint! 更新 2:看起来真的只是 NSLayoutConstraint 改变了游戏规则。随着@999

以上是关于Swift - StackView 和添加约束,以编程方式添加视图到堆栈 - 加载后调整单元格高度?的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 以编程方式刷新约束

在 Swift 中以编程方式将视图添加到 stackview

带有约束的滚动视图中的iOS Swift stackview

StackView 高度 Swift

按钮stackView间距不起作用-Swift-以编程方式

Stackview内的布局约束(以编程方式快速移动)