SwiftUI 如何在 HStack 中对齐 child 视图
SwiftUI How to align child views inside HStack
我和这个问题有类似的问题(还没有回答):SwiftUI HStack with GeometryReader and paddings
不同的是,我的目标是在 HStack 中对齐两个视图,左视图获得可用宽度的 1/3,右视图获得可用宽度的 2/3。
在 ChildView 中使用 GeometryReader
会打乱整个布局,因为它会填满高度。
这是我的示例代码:
struct ContentView: View {
var body: some View {
VStack {
VStack(spacing: 5) {
ChildView().background(Color.yellow.opacity(0.4))
ChildView().background(Color.yellow.opacity(0.4))
Spacer()
}
.padding()
Spacer()
Text("Some random Text")
}
}
}
struct ChildView: View {
var body: some View {
GeometryReader { geo in
HStack {
Text("Left")
.frame(width: geo.size.width * (1/3))
Text("Right")
.frame(width: geo.size.width * (2/3))
.background(Color.red.opacity(0.4))
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green.opacity(0.4))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
结果是:
现在,如果将此视图嵌入到其他视图中,布局将完全混乱:
例如在 ScrollView
内
那么,如何实现拥有一个 HStack
-ChildView 的预期结果,它填充它获得的 space 并将它(1/3,2/3)分配给它的两个 child仁?
编辑
如回答中所述,我也忘记添加HStack(spacing: 0)
。遗漏它是右 child 容器溢出的原因。
您可以为视图大小创建自定义 PreferenceKey
。 是一个例子:
struct ViewSizeKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
然后,创建一个将计算其大小并将其分配给 ViewSizeKey
:
的视图
struct ViewGeometry: View {
var body: some View {
GeometryReader { geometry in
Color.clear
.preference(key: ViewSizeKey.self, value: geometry.size)
}
}
}
现在,您可以在 ChildView
中使用它们(即使它包含在 ScrollView
中):
struct ChildView: View {
@State var viewSize: CGSize = .zero
var body: some View {
HStack(spacing: 0) { // no spacing between HStack items
Text("Left")
.frame(width: viewSize.width * (1 / 3))
Text("Right")
.frame(width: viewSize.width * (2 / 3))
.background(Color.red.opacity(0.4))
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green.opacity(0.4))
.background(ViewGeometry()) // calculate the view size
.onPreferenceChange(ViewSizeKey.self) {
viewSize = [=12=] // assign the size to `viewSize`
}
}
}
我和这个问题有类似的问题(还没有回答):SwiftUI HStack with GeometryReader and paddings
不同的是,我的目标是在 HStack 中对齐两个视图,左视图获得可用宽度的 1/3,右视图获得可用宽度的 2/3。
在 ChildView 中使用 GeometryReader
会打乱整个布局,因为它会填满高度。
这是我的示例代码:
struct ContentView: View {
var body: some View {
VStack {
VStack(spacing: 5) {
ChildView().background(Color.yellow.opacity(0.4))
ChildView().background(Color.yellow.opacity(0.4))
Spacer()
}
.padding()
Spacer()
Text("Some random Text")
}
}
}
struct ChildView: View {
var body: some View {
GeometryReader { geo in
HStack {
Text("Left")
.frame(width: geo.size.width * (1/3))
Text("Right")
.frame(width: geo.size.width * (2/3))
.background(Color.red.opacity(0.4))
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green.opacity(0.4))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
结果是:
现在,如果将此视图嵌入到其他视图中,布局将完全混乱:
例如在 ScrollView
那么,如何实现拥有一个 HStack
-ChildView 的预期结果,它填充它获得的 space 并将它(1/3,2/3)分配给它的两个 child仁?
编辑
如回答中所述,我也忘记添加HStack(spacing: 0)
。遗漏它是右 child 容器溢出的原因。
您可以为视图大小创建自定义 PreferenceKey
。
struct ViewSizeKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
然后,创建一个将计算其大小并将其分配给 ViewSizeKey
:
struct ViewGeometry: View {
var body: some View {
GeometryReader { geometry in
Color.clear
.preference(key: ViewSizeKey.self, value: geometry.size)
}
}
}
现在,您可以在 ChildView
中使用它们(即使它包含在 ScrollView
中):
struct ChildView: View {
@State var viewSize: CGSize = .zero
var body: some View {
HStack(spacing: 0) { // no spacing between HStack items
Text("Left")
.frame(width: viewSize.width * (1 / 3))
Text("Right")
.frame(width: viewSize.width * (2 / 3))
.background(Color.red.opacity(0.4))
}
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.green.opacity(0.4))
.background(ViewGeometry()) // calculate the view size
.onPreferenceChange(ViewSizeKey.self) {
viewSize = [=12=] // assign the size to `viewSize`
}
}
}