来自 UIKit,我发现在 SwiftUI 中很难达到预期的结果。我假设我会陷入约束驱动布局中,以了解 SwiftUI 方法。
假设以下布局:
在具有“常规”屏幕的设备上,水平空间应按 1:1 分为顶部和底部部分。
顶部容器包含固定高度的三个视图,应位于容器的顶部、中心和底部。
三个视图有一些最小间距,例如20 像素。如果有足够的空间,间距可以更大,但绝不能低于 20 像素。
在较小的设备上,顶部容器可以缩小到一定程度。但永远不会太小,以至于会违反子视图的固定宽度及其间距。在这种情况下,顶部和底部容器之间的比例将不再是 1:1,而是例如2:3.
在 iPad 等较大设备上,顶部容器只会增长到某个最大值。高度。在这种情况下,顶部和底部容器之间的比例也不再是 1:1。
底部容器视图仅包含一个视图,该视图应始终填充可用空间。
使用 UIKit 中的约束来解决这个问题是没有问题的。我知道“常规”、“较小”和“较大”设备并不是实际的尺寸类别。这只是为了说明。
但是在 SwiftUI 中如何解决这个问题?
基本布局当然是直接的:
VStack(spacing: 0) {
VStack {
TopView()
Spacer()
CenterView()
Spacer()
BottomView()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.red)
VStack {
FillView()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.green)
}
但是如何实现top-container的min-和maxHeight呢?是否可以不使用
GeometryReader
而仅使用相对值来做到这一点?
当底部容器因其内容而变大时,如何避免将顶部容器收缩到给定的最小高度以下?
我认为您可以通过一些小更改来非常接近您的要求:
VStack
的 Spacer
将在其包含的视图之间添加一些(默认)间距,因此这包括 Spacer
周围的一些额外间距。为了强制执行 20 点最小间距,我建议在 spacing: 20
上使用 VStack
,然后删除 Spacer
并在 maxHeight: .infinity
上设置 CenterView
:VStack(spacing: 20) {
TopView()
CenterView()
.frame(maxHeight: .infinity)
BottomView()
}
maxHeight
上设置有限的VStack
,而不是.infinity
:VStack(spacing: 20) {
// ...
}
.padding()
.frame(maxWidth: .infinity, maxHeight: 400)
.background(.red)
FillView
上设置最小高度(根据阈值高度计算)来实现类似的效果:FillView()
.frame(maxWidth: .infinity, minHeight: 200, maxHeight: .infinity)
.background(.green)
请注意,所有 iPhone 的横向高度甚至比最小的 iPhone 纵向高度还要小。
把它们放在一起:
VStack(spacing: 0) {
VStack(spacing: 20) {
TopView()
CenterView()
.frame(maxHeight: .infinity)
BottomView()
}
.padding()
.frame(maxWidth: .infinity, maxHeight: 400)
.background(.red)
FillView()
.frame(maxWidth: .infinity, minHeight: 200, maxHeight: .infinity)
.background(.green)
}
使用比率分配空间的另一种方法是使用自定义
Layout
。按权重水平分布视图的示例实现可以在 SwiftUI How to Set Specific Width Ratios for Child Elements in an HStack(这是我的答案)的答案中找到。