I have a fairly basic SwiftUI view heirarcy that I'm attempting to insert a divider into, however the divider is sizing itself to some obscure value and pushing the parent view out to meet it. Every other view in the heirarchy is behaving correctly and the parent view is wrapping the largest child, as expected.
I've searched and searched and just can't find any insight into this behaviour - so I'm asking you good folks for some thoughs.
View code:
Form {
HStack(alignment: .top) {
VStack(alignment: .trailing) {
Picker("Paper Size:", selection: $viewModel.layoutParameters.paperSize) {
ForEach(PrintSize.allCases, id: \.self) {
Text($0.description)
}
}
.pickerStyle(.menu)
Picker(selection: $viewModel.layoutParameters.margin) {
ForEach(Margin.allCases, id: \.self) {
Text($0.description)
}
} label: {
Text("Margins:")
.padding(.leading, 15) // This is janky, find a better way to do it.
}
.pickerStyle(.menu)
}
Divider()
Picker("Default Print Size:", selection: $viewModel.layoutParameters.printSize) {
ForEach(PrintSize.allCases, id: \.self) {
Text($0.description)
}
}
.pickerStyle(.menu)
}
}
.padding(8)
Exhibited behaviour with divider:
Bonus points if you can give me a way to nudge the Margins label over without explicitly applying padding.
Both the issues that you describe can be solved by using overlays.
Divider
is greedy and expands to use all the space available, just like a Spacer
. To constrain it to the height of the HStack
, just put it in an overlay over the HStack
. By default, the overlay will be aligned to the center of the HStack
. This is perfect, because the two Picker
will have equal widths, so the Divider
will automatically be positioned in the middle between them. However, two extra steps are needed to get it looking right:Divider
is normally determined by the stack that contains it, or horizontal by detault. Since you want it to be vertical, it needs to be nested inside a dummy HStack
.spacing
that is used by the HStack
, since there is now only one space between the two Picker
.Here is an updated version of your example with the two changes applied:
Form {
HStack(alignment: .top, spacing: 20) { // <- spacing added
VStack(alignment: .trailing) {
Picker("Paper Size:", selection: $viewModel.layoutParameters.paperSize) {
ForEach(PrintSize.allCases, id: \.self) {
Text($0.description)
}
}
.pickerStyle(.menu)
Picker(selection: $viewModel.layoutParameters.margin) {
ForEach(Margin.allCases, id: \.self) {
Text($0.description)
}
} label: {
Text("Paper Size:")
.hidden()
.overlay(alignment: .trailing) {
Text("Margins:")
}
// .padding(.leading, 15) // This is janky, find a better way to do it.
}
.pickerStyle(.menu)
}
// Divider()
Picker("Default Print Size:", selection: $viewModel.layoutParameters.printSize) {
ForEach(PrintSize.allCases, id: \.self) {
Text($0.description)
}
}
.pickerStyle(.menu)
}
.overlay {
HStack {
Divider()
}
}
}
.padding(8)