提问人:Jacob King 提问时间:11/10/2023 最后编辑:Dávid PásztorJacob King 更新时间:11/11/2023 访问量:74
SwiftUI Divider 无法调整自身大小以适应父视图?
SwiftUI Divider not sizing itself to fit parent view?
问:
我有一个相当基本的 SwiftUI 视图层次结构,我正在尝试在其中插入一个分隔符,但是分隔符正在将自己调整为某个模糊的值,并将父视图推出以满足它。层次结构中的所有其他视图都运行正常,并且父视图正在包装最大的子视图,正如预期的那样。
我已经搜索了又搜索,只是找不到对这种行为的任何见解 - 所以我问你们一些好人。
查看代码:
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)
如果您能给我一种方法来在不显式应用填充的情况下将 Margins 标签推过来,那就加分了。
答:
您描述的两个问题都可以通过使用叠加来解决。
- A 是贪婪的,并扩展以使用所有可用空间,就像 .要将其限制在 的高度,只需将其放在 上面的覆盖层中即可。默认情况下,叠加层将与 .这是完美的,因为两者的宽度相等,因此将自动定位在它们之间的中间。但是,需要两个额外的步骤才能使其看起来正确:
Divider
Spacer
HStack
HStack
HStack
Picker
Divider
- a 的方向通常由包含它的堆栈决定,或由 detault 水平确定。由于您希望它是垂直的,因此需要将其嵌套在虚拟 .
Divider
HStack
- 您可能希望增加 ,因为现在两者之间只有一个空格。
spacing
HStack
Picker
- 如果希望“边距”标签的宽度与“纸张尺寸”标签的宽度相同,则可以使用较长标签的隐藏版本来建立所需的占用空间。然后在叠加层中显示较短的标签。
下面是示例的更新版本,其中应用了两项更改:
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)
评论
hidden
fixedSized
Divider
.pickerStyle(.menu)
请注意,您使用的是 Xcode 预览。预览的行为与正常运行应用的行为略有不同。
如果您正常运行应用程序,则两种情况下的窗口大小将相同(无论 macOS 默认窗口大小是多少,或者存储在您的首选项中的任何内容),并且您可以将两者的大小调整为尽可能小的大小。您看到的尺寸只是 Xcode 预览的怪癖。
请注意,如果没有 ,您仍然可以将窗口的大小调整为任意大,并且位于中间,而无需更改其高度,并且下方和上方都有很多空白区域。另一方面,s 会水平扩展,s 的宽度可以改变。Divider
HStack
Picker
HStack
“预览”尝试显示您的视图,而不显示任何周围的空白区域。这就是为什么你会得到一个非常适合的窗口,当没有.请注意,预览窗口的宽度是默认的 macOS 窗口宽度。这是因为选择者很贪婪,并试图占用尽可能多的水平空间 - 预览必须在某个地方停止它。HStack
Divider
Divider
s也很贪婪,并试图尽可能地垂直扩张。当存在 时,当 的高度大于拾取器的总和时,所有 都会在顶部对齐(因为)。此外,上下不再有“周围的空白区域”,因为总有填充该空间。预览会选择 macOS 窗口的默认高度(同样,它必须在某处停止扩展),该数字大于选取器的总高度。Divider
Text
HStack(alignment: .top)
HStack
Divider
预览本可以设计为将窗口大小调整为最小大小,但事实并非如此。我想很多观点这样看起来会相当局促。
我不确定有没有办法让预览显示最小大小窗口。不过,您可以强制预览使用特定大小的窗口:
#Preview(traits: .fixedLayout(width: 500, height: 100)) {
ContentView()
}
您也可以尝试穿上 ,但这会调整为“理想尺寸”,而不是最小尺寸。“理想尺寸”仍然比最小尺寸大得多。.fixedSize
HStack
// you can also set the ideal size
// .frame(idealHeight: 100)
.fixedSize(horizontal: false, vertical: true)
至于对齐标签,我会使用:Grid
Grid(alignment: .trailing, horizontalSpacing: 8, verticalSpacing: 8) {
GridRow {
Text("Paper Size:")
Picker("", selection: .constant(1)) {
// Dummy data for the picker...
Text("Foo").tag(1)
}
}
GridRow {
Text("Margins:")
Picker("", selection: .constant(1)) {
Text("Bar").tag(1)
}
}
}
旁注:您可以放在 上,而不是每个选择器。它将这种风格应用于所有孩子。.pickerStyle(.menu)
HStack
评论
这个问题令人担忧。
您在使用 SwiftUI 视图层次结构时遇到的行为可能是由于 SwiftUI 计算视图布局的方式所致。默认情况下,视图将展开以填充可用宽度。如果将其放置在具有灵活宽度的容器视图中,这可能会导致意外的布局问题,例如 .
你可以试试这个:Form
Divider
Divider
HStack
Form {
// Your existing code...
HStack(alignment: .top) {
VStack(alignment: .trailing) {
// Your existing code...
}
Divider()
.frame(height: 1) // Set the height of the Divider to 1 point
.padding(.vertical, 8) // Add vertical padding to match the other views
.background(Color.gray) // Optionally, add a background color to the Divider
.padding(.horizontal, 8) // Add horizontal padding to match the other views
}
// Your existing code...
}
通过使用 frame 修改器将 的高度设置为 1 磅,您可以独立于 .此外,还可以添加填充和背景色,以匹配视图层次结构中其他视图的样式。Divider
HStack
尝试此修改,看看它是否解决了 SwiftUI 视图层次结构中的布局问题。Divider
评论
.fixedSize()