1

I have a 4 x 1 UILabel matrix in a horizontal stackview I would like columns 1 and 3 to be the same width BUT narrower than columns 2 and 4. I have tried .fillproportionally, and others. I understood that this was possible... however, a solution evades me and Google hasn't turned anything up. Any help or a point in the right direction would be helpful. Thank you. I am not using Storyboards.

user3194306
  • 81
  • 1
  • 7
  • How do you want to determine your "column" widths? C1 & C3 should be equal, but based on what? The one with more text? And, narrower than C2 & C4, but again, based on what? Suppose your "column" text is `a | word | longer text | short`? How do you want that to get laid-out? – DonMag Apr 27 '20 at 18:12
  • C1 should be a third of C2 and C3 should be a third of C4. The words in C1 and C3 are annotations as single words. The content in C2 and C4 is calculated values and therefore variable. – user3194306 Apr 28 '20 at 20:07
  • hmmm.. so, `C1 == C2 * 0.333` and `C3 == C4 * 0.333` but C2 may not be equal to C4, so C1 & C3 will be different widths? – DonMag Apr 28 '20 at 21:08
  • Much easier to understand what you're going for if you give us a few examples of the content. – DonMag Apr 28 '20 at 21:10
  • For example, in this image: https://i.stack.imgur.com/AwXuD.png all **C1** labels are 1/3 the width of **C2** (cyan), and all **C3** labels are 1/3 the width of **C4** (green). But, as is obvious, **C1** widths are **not equal** to **C3** widths. – DonMag Apr 28 '20 at 21:34
  • C1 will hold the following HOLDING, BOOK, P/L. C3 will hold the following PAID, MARKET, WEIGHT. I really appreciate your help however I thought that the answer might lie with the contraints and multiples thereof, within the UIStackview – user3194306 Apr 29 '20 at 08:49
  • You *can* do this with stackView / constraints / multipliers / etc (that's what I did in the image I linked), but you still haven't clarified what ***exactly*** you want to do. Suppose `C2-w` is **120** and `C4-w` is **180**. You want `C1-w` to be **1/3 of C2 = 40** and you want `C3-w` tp be **1/3 of C4 = 60** ... ***AND*** you want `C1-w == C3-w`. So, how can you have `40 == 60`? That's why I said show actual examples of your "column content" --- better yet, lay out a couple examples manually and post that image to make it clear. – DonMag Apr 29 '20 at 13:06
  • https://i.stack.imgur.com/uPha8.png – user3194306 Apr 30 '20 at 14:15
  • I would like columns 1 and 3 to be the same width BUT narrower than columns 2 and 4.See visual. – user3194306 Apr 30 '20 at 14:19

2 Answers2

0

You can create your grid:

enter image description here

as you described:

C1-w == 1/3 of C2-w
C3-w == C1-w
C4-w == C2-w

pretty much with that description:

enter image description here

with the stack view .distribution = .fill

Here's a complete example:

class ColumnStackViewController: UIViewController {

    let outerStack: UIStackView = {
        let v = UIStackView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.axis = .vertical
        v.alignment = .fill
        v.distribution = .fill
        v.spacing = 8
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // create "header row" stack view
        let headerRowStack = UIStackView()
        headerRowStack.axis = .horizontal
        headerRowStack.spacing = 4

        // create 4 labels for header row
        let headerC1 = UILabel()
        let headerC2 = UILabel()
        let headerC3 = UILabel()
        let headerC4 = UILabel()

        headerC1.text = "C1"
        headerC2.text = "C2"
        headerC3.text = "C3"
        headerC4.text = "C4"

        [headerC1, headerC2, headerC3, headerC4].forEach { v in
            // give each "header" label a background color, so we can see the frames
            v.backgroundColor = .yellow
            v.textAlignment = .center
            headerRowStack.addArrangedSubview(v)
        }

        NSLayoutConstraint.activate([
            // constrain c1 width to 1/3 of c2 width
            headerC1.widthAnchor.constraint(equalTo: headerC2.widthAnchor, multiplier: 1.0 / 3.0),
            // constrain c3 width equal to c1 width
            headerC3.widthAnchor.constraint(equalTo: headerC1.widthAnchor),
            // constrain c4 width equal to c2 width
            headerC4.widthAnchor.constraint(equalTo: headerC2.widthAnchor),
        ])

        outerStack.addArrangedSubview(headerRowStack)

        let c1Vals = ["HOLDING", "BOOK", "P/L"]
        let c3Vals = ["PAID", "MARKET", "WEIGHT"]

        for i in 0..<c1Vals.count {

            // create a "row" stack view
            let rowStack = UIStackView()
            rowStack.axis = .horizontal
            rowStack.spacing = headerRowStack.spacing

            // add it to outer stack view
            outerStack.addArrangedSubview(rowStack)

            let rowC1 = UILabel()
            let rowC2 = UILabel()
            let rowC3 = UILabel()
            let rowC4 = UILabel()

            rowC1.text = c1Vals[i]
            rowC3.text = c3Vals[i]

            rowC2.text = "row \(i+1) c2 data"
            rowC4.text = "row \(i+1) c4 data"

            [rowC1, rowC2, rowC3, rowC4].forEach { v in
                // give each row-label a border
                v.layer.borderColor = UIColor.red.cgColor
                v.layer.borderWidth = 0.5
                // set the font
                v.font = UIFont.systemFont(ofSize: 14.0, weight: .light)
                // add it to the row stack view
                rowStack.addArrangedSubview(v)
            }

            // constrain each row-label width to the header-row label width
            for (hLabel, rowLabel) in zip([headerC1, headerC2, headerC3, headerC4], [rowC1, rowC2, rowC3, rowC4]) {
                rowLabel.widthAnchor.constraint(equalTo: hLabel.widthAnchor).isActive = true
            }

        }

        view.addSubview(outerStack)

        // respect safe area
        let g = view.safeAreaLayoutGuide

        NSLayoutConstraint.activate([
            // constrain outer stack view to Top / Leading / Trailing with 20-pt "padding"
            outerStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            outerStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            outerStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
        ])

    }

}

which produces this result:

enter image description here

Note: you'll have to use a pretty small font to fit that layout on a small device:

enter image description here

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • 1
    Hi This is all i ended needing v1.widthAnchor.constraint(equalTo: v2.widthAnchor, multiplier: 0.5, constant: 0).isActive = true v3.widthAnchor.constraint(equalTo: v1.widthAnchor ).isActive = true v4.widthAnchor.constraint(equalTo: v2.widthAnchor ).isActive = true – user3194306 May 03 '20 at 13:32
  • @user3194306 /UIStackView observes your layout w/constraints. I had horiz. UIStackView w/3 small images & 1 text label, where SV cell size was calc'd based on image size, & squeezed label (ellipsis). Intrinsic size wasn't set, compression or something. Setting layout constraint width anchor fixed it! UIStackView accommodated, however, changing the width of the the item increased size of image items of the stackView with distribution =fillEqually, .fillProportionally, ... .centerEqually less so. So you may have to play around SV variables to get it right. https://nshipster.com/uistackview/ – clearlight Apr 18 '23 at 00:23
0

This is all i ended needing v1.widthAnchor.constraint(equalTo: v2.widthAnchor, multiplier: 0.5, constant: 0).isActive = true v3.widthAnchor.constraint(equalTo: v1.widthAnchor ).isActive = true v4.widthAnchor.constraint(equalTo: v2.widthAnchor ).isActive = true

user3194306
  • 81
  • 1
  • 7