我有一个标题 View ,它使用 edgesIgnoringSafeArea
将其背景扩展到状态栏下方。要正确对齐标题 View 的内容/ subview ,我需要来自 GeometryReader
的 safeAreaInsets
。但是,当使用 GeometryReader
时,我的 View 不再具有合适的尺寸。
不使用GeometryReader
的代码
struct MyView : View {
var body: some View {
VStack(alignment: .leading) {
CustomView()
}
.padding(.horizontal)
.padding(.bottom, 64)
.background(Color.blue)
}
}
预览
代码使用 GeometryReader
struct MyView : View {
var body: some View {
GeometryReader { geometry in
VStack(alignment: .leading) {
CustomView()
}
.padding(.horizontal)
.padding(.top, geometry.safeAreaInsets.top)
.padding(.bottom, 64)
.background(Color.blue)
.fixedSize()
}
}
}
预览
有没有一种方法可以在不修改底层 View 大小的情况下使用 GeometryReader
?
最佳答案
标题中问题的答案:
- 可以将
GeometryReader
包装在.overlay()
或.background()
中。这样做将减轻 GeometryReader 的布局更改效果。 View 将正常布局,GeometryReader 将扩展到 View 的完整大小,并将geometry
发送到其内容构建器闭包中。 - 也可以设置 GeometryReader 的 frame 来阻止它急于展开。
例如,此示例通过将 GeometryReader 包裹在覆盖层中来呈现蓝色矩形和位于矩形高度 3/4 处的“Hello world”文本(而不是矩形填满所有可用空间):
struct MyView : View {
var body: some View {
Rectangle()
.fill(Color.blue)
.frame(height: 150)
.overlay(GeometryReader { geo in
Text("Hello world").padding(.top, geo.size.height * 3 / 4)
})
Spacer()
}
}
另一个通过在 GeometryReader 上设置框架来实现相同效果的示例:
struct MyView : View {
var body: some View {
GeometryReader { geo in
Rectangle().fill(Color.blue)
Text("Hello world").padding(.top, geo.size.height * 3 / 4)
}
.frame(height: 150)
Spacer()
}
}
但是,有一些注意事项/不是很明显的行为
1
View modifiers 适用于它们应用之前的所有内容,而不适用于之后的任何内容。在 .edgesIgnoringSafeArea(.all)
之后添加的叠加层/背景将遵守安全区域(不参与忽略安全区域)。
此代码在安全区域内呈现“Hello world”,而蓝色矩形忽略安全区域:
struct MyView : View {
var body: some View {
Rectangle()
.fill(Color.blue)
.frame(height: 150)
.edgesIgnoringSafeArea(.all)
.overlay(VStack {
Text("Hello world")
Spacer()
})
Spacer()
}
}
2
将 .edgesIgnoringSafeArea(.all)
应用到背景使 GeometryReader 忽略 SafeArea:
struct MyView : View {
var body: some View {
Rectangle()
.fill(Color.blue)
.frame(height: 150)
.overlay(GeometryReader { geo in
VStack {
Text("Hello world")
// No effect, safe area is set to be ignored.
.padding(.top, geo.safeAreaInsets.top)
Spacer()
}
})
.edgesIgnoringSafeArea(.all)
Spacer()
}
}
可以通过添加多个叠加层/背景来组成多个布局。
3
测量的几何图形将可用于 GeometryReader 的内容。不以 parent 或 sibling 的观点;即使值被提取到 State 或 ObservableObject 中。如果发生这种情况,SwiftUI 将发出运行时警告:
struct MyView : View {
@State private var safeAreaInsets = EdgeInsets()
var body: some View {
Text("Hello world")
.edgesIgnoringSafeArea(.all)
.background(GeometryReader(content: set(geometry:)))
.padding(.top, safeAreaInsets.top)
Spacer()
}
private func set(geometry: GeometryProxy) -> some View {
self.safeAreaInsets = geometry.safeAreaInsets
return Color.blue
}
}
关于SwiftUI - 在不修改 View 大小的情况下使用 GeometryReader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56859095/