VStack 中的 SwiftUI 布局,其中一个 child 提供了 maxHeight 但可以使用小于该高度
SwiftUI layout in VStack where one child is offered a maxHeight but can use less than that height
我正在尝试在包含两个 children 的 VStack
中构建布局。第一个 child 应该占用第二个 child 未使用的所有可用 space。第二个 child 有一个基于其自身内容的首选大小。我想将第二个 child 的高度限制为最大高度,但它应该能够小于最大值(当它自己的内容不能使用所有高度时)。这应该都响应根视图大小,即 VStack
的 parent(因为设备可以旋转)。
我的尝试使用了 .frame(maxHeight: n)
修饰符,它似乎无条件地占据了整个 n
点的高度,即使被修改的视图没有使用它。这导致在 VStack
的第二个 child 上方和下方呈现白色 space。这个问题显示在下面的纵向预览中 - hasIdealSizeView
只有 57.6pts 的高度,但是包裹该视图的框架有 75pts 的高度。
import SwiftUI
struct StackWithOneLimitedHeightChild: View {
var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
fullyExpandingView
hasIdealSizeView
.frame(maxHeight: geometry.size.height / 4)
}
}
}
var fullyExpandingView: some View {
Rectangle()
.fill(Color.blue)
}
var hasIdealSizeView: some View {
HStack {
Rectangle()
.aspectRatio(5/3, contentMode: .fit)
Rectangle()
.aspectRatio(5/3, contentMode: .fit)
}
// the following modifier just prints out the resulting height of this view in the layout
.overlay(alignment: .center) {
GeometryReader { geometry in
Text("Height: \(geometry.size.height)")
.font(.system(size: 12.0))
.foregroundColor(.red)
}
}
}
}
struct StackWithOneLimitedHeightChild_Previews: PreviewProvider {
static var previews: some View {
Group {
StackWithOneLimitedHeightChild()
.previewDisplayName("Portrait")
.previewLayout(PreviewLayout.fixed(width: 200, height: 300))
StackWithOneLimitedHeightChild()
.previewDisplayName("Landscape")
.previewLayout(PreviewLayout.fixed(width: 300, height: 180))
}
}
}
观察到的结果与文档和在线博客文章中描述 .frame(maxHeight: n)
修饰符的方式一致(flow chart here 非常有帮助)。尽管如此,我似乎找不到另一种方法来构建这种类型的布局。
相关问题:.frame(maxHeight: n)
的预期用例是什么?通过无条件地将视图包装在高度至少为 n
点的框架中,这似乎与我的预期相反。它似乎与 .frame(height: n)
没有什么不同,对提供的高度使用明确的值。
可能有很短的方法可以解决这个问题,但与此同时,这就是我所做的。
首先,我为您的 hasIdealSizeView 创建了一个结构,并将其设为 return 一个 GeometryProxy,这样我就可以 return HStack 的高度,在这种情况下,与您在文本上打印的高度相同看法。然后我使用 return 代理检查高度是否大于最大值,如果是,我将其设置为最大值,否则,将高度设置为零,这基本上允许原生 SwiftUI 灵活身高:
//
// ContentView.swift
// Test
//
// Created by Denzel Anderson on 3/16/22.
//
import SwiftUI
struct StackWithOneLimitedHeightChild: View {
@State var viewHeight: CGFloat = 0
var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
fullyExpandingView
.overlay(Text("\(viewHeight)"))
// GeometryReader { geo in
hasIdealSizeView { proxy in
viewHeight = proxy.size.height
}
.frame(height: viewHeight > geometry.size.height / 4 ? geometry.size.height / 4:nil)
}
.background(Color.green)
}
}
var fullyExpandingView: some View {
Rectangle()
.fill(Color.blue)
}
}
struct hasIdealSizeView: View {
var height: (GeometryProxy)->()
var body: some View {
HStack {
Rectangle()
.fill(.white)
.aspectRatio(5/3, contentMode: .fit)
Rectangle()
.fill(.white)
.aspectRatio(5/3, contentMode: .fit)
}
// the following modifier just prints out the resulting height of this view in the layout
.overlay(alignment: .center) {
GeometryReader { geometry in
Text("Height: \(geometry.size.height)")
.font(.system(size: 12.0))
.foregroundColor(.red)
.onAppear {
height(geometry)
}
}
}
}
}
本例中 .minHeight 的行为很奇怪,远非直观。但我找到了一个使用稍微不同路线的解决方案:
这定义了展开视图的 minHeight(以在纵向模式下获得所需的布局),但向第二个添加了 .layoutPriority,使其首先定义自己,然后将剩余的 space 提供给上视图。
var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
fullyExpandingView
.frame(minHeight: geometry.size.height / 4 * 3)
hasIdealSizeView
.layoutPriority(1)
}
}
}
我正在尝试在包含两个 children 的 VStack
中构建布局。第一个 child 应该占用第二个 child 未使用的所有可用 space。第二个 child 有一个基于其自身内容的首选大小。我想将第二个 child 的高度限制为最大高度,但它应该能够小于最大值(当它自己的内容不能使用所有高度时)。这应该都响应根视图大小,即 VStack
的 parent(因为设备可以旋转)。
我的尝试使用了 .frame(maxHeight: n)
修饰符,它似乎无条件地占据了整个 n
点的高度,即使被修改的视图没有使用它。这导致在 VStack
的第二个 child 上方和下方呈现白色 space。这个问题显示在下面的纵向预览中 - hasIdealSizeView
只有 57.6pts 的高度,但是包裹该视图的框架有 75pts 的高度。
import SwiftUI
struct StackWithOneLimitedHeightChild: View {
var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
fullyExpandingView
hasIdealSizeView
.frame(maxHeight: geometry.size.height / 4)
}
}
}
var fullyExpandingView: some View {
Rectangle()
.fill(Color.blue)
}
var hasIdealSizeView: some View {
HStack {
Rectangle()
.aspectRatio(5/3, contentMode: .fit)
Rectangle()
.aspectRatio(5/3, contentMode: .fit)
}
// the following modifier just prints out the resulting height of this view in the layout
.overlay(alignment: .center) {
GeometryReader { geometry in
Text("Height: \(geometry.size.height)")
.font(.system(size: 12.0))
.foregroundColor(.red)
}
}
}
}
struct StackWithOneLimitedHeightChild_Previews: PreviewProvider {
static var previews: some View {
Group {
StackWithOneLimitedHeightChild()
.previewDisplayName("Portrait")
.previewLayout(PreviewLayout.fixed(width: 200, height: 300))
StackWithOneLimitedHeightChild()
.previewDisplayName("Landscape")
.previewLayout(PreviewLayout.fixed(width: 300, height: 180))
}
}
}
观察到的结果与文档和在线博客文章中描述 .frame(maxHeight: n)
修饰符的方式一致(flow chart here 非常有帮助)。尽管如此,我似乎找不到另一种方法来构建这种类型的布局。
相关问题:.frame(maxHeight: n)
的预期用例是什么?通过无条件地将视图包装在高度至少为 n
点的框架中,这似乎与我的预期相反。它似乎与 .frame(height: n)
没有什么不同,对提供的高度使用明确的值。
可能有很短的方法可以解决这个问题,但与此同时,这就是我所做的。 首先,我为您的 hasIdealSizeView 创建了一个结构,并将其设为 return 一个 GeometryProxy,这样我就可以 return HStack 的高度,在这种情况下,与您在文本上打印的高度相同看法。然后我使用 return 代理检查高度是否大于最大值,如果是,我将其设置为最大值,否则,将高度设置为零,这基本上允许原生 SwiftUI 灵活身高:
//
// ContentView.swift
// Test
//
// Created by Denzel Anderson on 3/16/22.
//
import SwiftUI
struct StackWithOneLimitedHeightChild: View {
@State var viewHeight: CGFloat = 0
var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
fullyExpandingView
.overlay(Text("\(viewHeight)"))
// GeometryReader { geo in
hasIdealSizeView { proxy in
viewHeight = proxy.size.height
}
.frame(height: viewHeight > geometry.size.height / 4 ? geometry.size.height / 4:nil)
}
.background(Color.green)
}
}
var fullyExpandingView: some View {
Rectangle()
.fill(Color.blue)
}
}
struct hasIdealSizeView: View {
var height: (GeometryProxy)->()
var body: some View {
HStack {
Rectangle()
.fill(.white)
.aspectRatio(5/3, contentMode: .fit)
Rectangle()
.fill(.white)
.aspectRatio(5/3, contentMode: .fit)
}
// the following modifier just prints out the resulting height of this view in the layout
.overlay(alignment: .center) {
GeometryReader { geometry in
Text("Height: \(geometry.size.height)")
.font(.system(size: 12.0))
.foregroundColor(.red)
.onAppear {
height(geometry)
}
}
}
}
}
本例中 .minHeight 的行为很奇怪,远非直观。但我找到了一个使用稍微不同路线的解决方案:
这定义了展开视图的 minHeight(以在纵向模式下获得所需的布局),但向第二个添加了 .layoutPriority,使其首先定义自己,然后将剩余的 space 提供给上视图。
var body: some View {
GeometryReader { geometry in
VStack(spacing: 0) {
fullyExpandingView
.frame(minHeight: geometry.size.height / 4 * 3)
hasIdealSizeView
.layoutPriority(1)
}
}
}