GeometryReader 计算视图的总高度
GeometryReader to calculate total height of views
我有一个固定宽度和高度的主视图,因为这个视图将被转换成 PDF。接下来,我有一个子视图数组,它们将垂直堆叠在主视图中。可能有更多的子视图可以容纳在主视图中,所以我需要一种方法来确保我不超过主视图的总高度。例如,如果我的数组中有八个子视图,但只有三个适合主视图,那么我需要在三个之后停止添加子视图。剩余的子视图将在新的主视图上重新开始该过程。
我的问题是,如果我使用 GeometryReader 获取视图的高度,首先我必须添加它。但是一旦添加了视图,再发现它是否超过了可用的总高度就来不及了。
下面显示了我如何在添加每个视图时获取它的高度。这没什么好继续的,我知道,但我很困惑。
更新:
我目前的策略是创建一个临时视图,我可以在其中添加子视图和 return 一个只有适合的数组。
struct PDFView: View {
var body: some View {
VStack {
ForEach(tasks) { task in
TaskRowView(task: task)
.overlay(
GeometryReader { geo in
// geo.size.height - to get height of current view
})
}
}
.layoutPriority(1)
}
}
您可以在一个地方获取总高度,如下所示:
VStack {
ForEach(tasks) { task in
TaskRowView(task: task)
}
}
.overlay(
GeometryReader { geo in
// geo.size.height // << move it here and get total height at once
})
一种可能的解决方案是使用 查看首选项。
您可以计算项目的总高度,然后在 onPreferenceChange
中将它们的 count
增加 1(直到 totalHeight
达到 maxHeight
)。
完整的实现如下:
- 创建自定义
PreferenceKey
以检索视图高度:
struct ViewHeightKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value += nextValue()
}
}
struct ViewGeometry: View {
var body: some View {
GeometryReader { geometry in
Color.clear
.preference(key: ViewHeightKey.self, value: geometry.size.height)
}
}
}
- 创建一个
TaskRowView
(任意身高):
struct TaskRowView: View {
let index: Int
var body: some View {
Text("\(index)")
.padding()
.background(Color.red)
}
}
- 在您看来使用自定义
PreferenceKey
:
struct ContentView: View {
@State private var count = 0
@State private var totalHeight: CGFloat = 0
@State private var maxHeightReached = false
let maxHeight: CGFloat = 300
var body: some View {
VStack {
Text("Total height: \(totalHeight)")
VStack {
ForEach(0 ..< count, id: \.self) {
TaskRowView(index: [=13=])
}
}
.background(ViewGeometry())
.onPreferenceChange(ViewHeightKey.self) {
totalHeight = [=13=]
print(count, totalHeight)
guard !maxHeightReached else { return }
if [=13=] < maxHeight {
count += 1
} else {
count -= 1
maxHeightReached = true
}
}
}
}
}
我有一个固定宽度和高度的主视图,因为这个视图将被转换成 PDF。接下来,我有一个子视图数组,它们将垂直堆叠在主视图中。可能有更多的子视图可以容纳在主视图中,所以我需要一种方法来确保我不超过主视图的总高度。例如,如果我的数组中有八个子视图,但只有三个适合主视图,那么我需要在三个之后停止添加子视图。剩余的子视图将在新的主视图上重新开始该过程。
我的问题是,如果我使用 GeometryReader 获取视图的高度,首先我必须添加它。但是一旦添加了视图,再发现它是否超过了可用的总高度就来不及了。
下面显示了我如何在添加每个视图时获取它的高度。这没什么好继续的,我知道,但我很困惑。
更新: 我目前的策略是创建一个临时视图,我可以在其中添加子视图和 return 一个只有适合的数组。
struct PDFView: View {
var body: some View {
VStack {
ForEach(tasks) { task in
TaskRowView(task: task)
.overlay(
GeometryReader { geo in
// geo.size.height - to get height of current view
})
}
}
.layoutPriority(1)
}
}
您可以在一个地方获取总高度,如下所示:
VStack {
ForEach(tasks) { task in
TaskRowView(task: task)
}
}
.overlay(
GeometryReader { geo in
// geo.size.height // << move it here and get total height at once
})
一种可能的解决方案是使用 查看首选项。
您可以计算项目的总高度,然后在 onPreferenceChange
中将它们的 count
增加 1(直到 totalHeight
达到 maxHeight
)。
完整的实现如下:
- 创建自定义
PreferenceKey
以检索视图高度:
struct ViewHeightKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value += nextValue()
}
}
struct ViewGeometry: View {
var body: some View {
GeometryReader { geometry in
Color.clear
.preference(key: ViewHeightKey.self, value: geometry.size.height)
}
}
}
- 创建一个
TaskRowView
(任意身高):
struct TaskRowView: View {
let index: Int
var body: some View {
Text("\(index)")
.padding()
.background(Color.red)
}
}
- 在您看来使用自定义
PreferenceKey
:
struct ContentView: View {
@State private var count = 0
@State private var totalHeight: CGFloat = 0
@State private var maxHeightReached = false
let maxHeight: CGFloat = 300
var body: some View {
VStack {
Text("Total height: \(totalHeight)")
VStack {
ForEach(0 ..< count, id: \.self) {
TaskRowView(index: [=13=])
}
}
.background(ViewGeometry())
.onPreferenceChange(ViewHeightKey.self) {
totalHeight = [=13=]
print(count, totalHeight)
guard !maxHeightReached else { return }
if [=13=] < maxHeight {
count += 1
} else {
count -= 1
maxHeightReached = true
}
}
}
}
}