1

I'm attempting to include a series of UITextFields, with corresponding UILabels, in a vertical UIStackView. I'm nesting each label/field pair in a horizontal UIStackView, and the width of the labels is hard-coded to the widest intrinsic width of all the labels, so that they line up nicely.

It very nearly works, but the horizontal stack views are not spaced evenly as expected (spacing = 5) and are bunched up and overlapping.

HOWVER, if I delete the line hFieldStack.alignment = .lastBaseline, then it all works perfectly.

I'm OK with deleting that line, as it looks fine. But I'm just curious as to why spacing in the outside stack view doesn't work when using lastBaseline alignment within the nested stack view.

stack view spacing issue

        stackView.axis = .vertical
        stackView.spacing = 5
        stackView.layoutMargins = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0)
        stackView.isLayoutMarginsRelativeArrangement = true

        if let titleLabel = titleLabel {
            stackView.addArrangedSubview(titleLabel)
        }
        
        if let messageLabel = messageLabel {
            stackView.addArrangedSubview(messageLabel)
        }
        
        if textFields.count == fieldLabels.count {
            for i in 0..<textFields.count {
                fieldLabels[i].widthAnchor.constraint(equalToConstant: 80).isActive = true
                let hFieldStack = UIStackView()
                hFieldStack.translatesAutoresizingMaskIntoConstraints = false
                hFieldStack.axis = .horizontal
                hFieldStack.alignment = .lastBaseline
                hFieldStack.spacing = 5
                hFieldStack.layoutMargins = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
                hFieldStack.isLayoutMarginsRelativeArrangement = true
                hFieldStack.addArrangedSubview(fieldLabels[i])
                hFieldStack.addArrangedSubview(textFields[i])
                stackView.addArrangedSubview(hFieldStack)
            }
        } else {
            logger.error("Field count doesn't match label count")
        }
Son of a Beach
  • 1,733
  • 1
  • 11
  • 29

1 Answers1

1

Curious...

It appears that, when setting the horizontal stack view's Alignment to .lastBaseline (also happens with .firstBaseline), Auto-layout is using the text field's _UITextFieldCanvasView to calculate the layout.

So, with a rounded-rect border, the actual frame of the text field is taller than the _UITextFieldCanvasView.

We can confirm this by inspecting the view hierarchy:

enter image description here

The labels are nicely baseline aligned with the text rendered in the _UITextFieldCanvasView... but the frames are obviously extending outside the stack view's framing.

While the docs do list .lastBaseline as. valid Alignment constant, it's somewhat telling that, in Storyboard / Interface Builder, the only Alignment options are Fill, Leading, Center and Trailing.

I've come across several actual Bugs related to StackViews --- so I think I would (personally) add this one to the list.

DonMag
  • 69,424
  • 5
  • 50
  • 86