【问题标题】:2D UiLabel Grid with UIStackView last column not filling up space. Does UIStackView honor ContentHuggingPriority?带有 UIStackView 最后一列的 2D UiLabel 网格未填满空间。 UIStackView 是否尊重 ContentHuggingPriority?
【发布时间】:2023-03-31 04:13:01
【问题描述】:

我正在尝试制作一个比使用 UICollectionView 完成某些小任务更容易制作网格的 UIControl。我正在使用 UIStackViews 的 UIStackView。那是垂直堆栈(列)的水平容器。问题是我需要一列作为扩展列来填充额外的空间。 UIStackView 是否尊重 setContentHuggingPriority 的设置? ,在这种情况下是我的垂直列之一。

我已经包含了一个游乐场来重现这个问题。

Link to visual showing the UILabel Grid where only one column should fill horizontally

这里是操场代码:

import Foundation
import UIKit
import PlaygroundSupport

class ViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white
        self.view = view

        let labMatrix = LabelMatrix( rows: 4, columns: 4)

        self.view.addSubview( labMatrix)

        labMatrix.labMatrix[0][0].text = "Test"
        labMatrix.frame = CGRect(x: 0, y: 0, width: 360, height: 520)
    }
}

class LabelMatrix : UIStackView {
    let rowCount : Int
    let colCount : Int

    var labMatrix = [[UILabel]]()

    required init(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    init ( rows: Int , columns : Int ) {
        rowCount = rows
        colCount = columns
        super.init(frame:.zero)
        create()
    }

    func create() {
        var columns : [UIStackView] = [UIStackView]()
        var rows : [UILabel] = [UILabel]()

        for acol in 0..<colCount {
            rows.removeAll()

            for arow in 0..<rowCount {
                let lab = UILabel()
                //                lab.translatesAutoresizingMaskIntoConstraints = false
                rows.append( lab )

                let str = "(\(arow),\(acol))"
                lab.text = str

                if !(arow%2 == 0) {
                    lab.backgroundColor = .lightGray
                } else {
                    lab.backgroundColor = .yellow
                }

                if arow == rowCount-1 {
                    print("This should make last row stretch vertically to fill any extra vertical space")
                    //                    lab.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 20), for: .vertical)
                    lab.setContentHuggingPriority(UILayoutPriority(rawValue: 20), for:.vertical)
                }
            }

            labMatrix.append( rows )
            let curCol = UIStackView(arrangedSubviews: rows)
            columns.append( curCol )

            curCol.axis = .vertical
            curCol.distribution = .fill
            curCol.spacing = 2
            curCol.alignment = .center

            if acol == colCount-1 {
                print("TODO Fix This. It should make only the last column(e.g. uistackview) strech to fill extra space")
                curCol.setContentHuggingPriority(UILayoutPriority(rawValue: 20), for:.horizontal)
            }
        }

        for col in columns {
            self.addArrangedSubview( col )
        }

        self.axis = .horizontal
        self.distribution = .fill
        self.alignment = .top
        self.spacing = 4
    }
}

PlaygroundPage.current.liveView = ViewController()

【问题讨论】:

    标签: ios swift cocoa-touch uistackview


    【解决方案1】:

    堆栈视图的行为在很多方面与其他视图略有不同 - 压缩和拥抱是两个值得注意的。

    堆栈视图的主要功能是排列其子视图。当它的一个或多个子视图具有自己的大小/压缩/拥抱属性时,堆栈视图的布局将(部分)由其子视图确定。

    要扩展您的最后一列(和最后一行),分布需要为 fill,并且该列/行中的视图(标签)需要修改其拥抱优先级。

    你可以得到这个游乐场结果:

    通过如下修改您的代码(cmets 应该清楚):

    import Foundation
    import UIKit
    import PlaygroundSupport
    
    class ViewController : UIViewController {
        override func loadView() {
            let view = UIView()
            view.backgroundColor = .white
            self.view = view
    
            let labMatrix = LabelMatrix( rows: 4, columns: 4)
    
            self.view.addSubview( labMatrix)
    
            labMatrix.labMatrix[0][0].text = "Test"
            labMatrix.frame = CGRect(x: 0, y: 0, width: 360, height: 520)
        }
    }
    
    class LabelMatrix : UIStackView {
        let rowCount : Int
        let colCount : Int
    
        var labMatrix = [[UILabel]]()
    
        required init(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        init ( rows: Int , columns : Int ) {
            rowCount = rows
            colCount = columns
            super.init(frame:.zero)
            create()
        }
    
        func create() {
            var columns : [UIStackView] = [UIStackView]()
            var rows : [UILabel] = [UILabel]()
    
            for acol in 0..<colCount {
                rows.removeAll()
    
                for arow in 0..<rowCount {
                    let lab = UILabel()
                    rows.append( lab )
    
                    let str = "(\(arow),\(acol))"
                    lab.text = str
    
                    // set the label text alignment to center
                    lab.textAlignment = .center
    
                    if !(arow%2 == 0) {
                        lab.backgroundColor = .lightGray
                    } else {
                        lab.backgroundColor = .yellow
                    }
    
                    if acol == colCount-1 {
                        print("This will allow the last column to stretch horizontally")
                        lab.setContentHuggingPriority(UILayoutPriority(rawValue: 20), for:.horizontal)
                    }
    
                    if arow == rowCount-1 {
                        print("This will allow the bottom row stretch vertically")
                        lab.setContentHuggingPriority(UILayoutPriority(rawValue: 20), for:.vertical)
                    }
    
                }
    
                labMatrix.append( rows )
                let curCol = UIStackView(arrangedSubviews: rows)
                columns.append( curCol )
    
                curCol.axis = .vertical
                curCol.distribution = .fill
                curCol.spacing = 2
                // .alignment should be .fill -- let the label center its own text
                curCol.alignment = .fill
    
                // not needed - hugging priority is controlled by the stack view's arranged subviews
                // if acol == colCount-1 {
                //  print("TODO Fix This. It should make only the last column(e.g. uistackview) strech to fill extra space")
                //  curCol.setContentHuggingPriority(UILayoutPriority(rawValue: 20), for:.horizontal)
                // }
    
            }
    
            for col in columns {
                self.addArrangedSubview( col )
            }
    
            self.axis = .horizontal
            self.distribution = .fill
            // .alignment needs to be .fill if you want the bottom row to expand vertically
            self.alignment = .fill
            self.spacing = 4
        }
    }
    
    PlaygroundPage.current.liveView = ViewController()
    

    【讨论】:

    • 我只是想说您的代码更改是一个巨大的改进。最后一列的文本可以左对齐,但底行的文本被搁置在填充空间的中间。当我将您的更改放在自定义 UITableViewCell 中时,它做了一些有趣的事情,但我需要再次测试它,如果它是可重复的,请发布它。但感谢这一巨大的改进。
    • 我相信您发现将最后一列更改为左对齐很容易。代码中的注释表明您希望底行填充空格...如果不这样做,请将self.alignment 更改回.top,并且您不需要if arow == rowCount-1 块中的lab.setContentHuggingPriority .通常,如果您不希望堆栈视图填充其边界,请不要限制其高度(通过框架或激活的约束)并让其内容决定其高度。
    猜你喜欢
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    • 2016-01-24
    • 2019-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多