4

我有一个固定宽度和高度的主视图,因为这个视图将被转换为 PDF。接下来,我有一组子视图,它们将垂直堆叠在主视图中。可用的子视图可能比主视图中的要多,所以我需要一种方法来确保我不超过主视图的总高度。例如,如果我的数组中有八个子视图,但只有三个适合主视图,那么我需要在三个之后停止添加子视图。剩余的子视图将在新的主视图上重新开始该过程。

我的问题是,如果我使用 GeometryReader 来获取视图的高度,首先我必须添加它。但是一旦添加了视图,再发现它是否超过了可用的总高度就为时已晚。

下面显示了我如何在添加每个视图时获取它的高度。我知道,这没什么好说的,但我很困惑。

更新:我目前的策略是创建一个临时视图,我可以在其中添加子视图并返回一个仅包含适合的数组。

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)
   }
}

在此处输入图像描述

4

2 回答 2

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
     })
于 2020-10-23T17:47:23.900 回答
1

一个可能的解决方案是使用View Preferences

您可以计算物品的总高度并将onPreferenceChange其增加count1(直到totalHeight达到maxHeight)。


这是完整的实现:

  1. 创建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)
        }
    }
}
  1. 创建一个TaskRowView(任意高度):
struct TaskRowView: View {
    let index: Int

    var body: some View {
        Text("\(index)")
            .padding()
            .background(Color.red)
    }
}
  1. 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: $0)
                }
            }
            .background(ViewGeometry())
            .onPreferenceChange(ViewHeightKey.self) {
                totalHeight = $0
                print(count, totalHeight)
                guard !maxHeightReached else { return }
                if $0 < maxHeight {
                    count += 1
                } else {
                    count -= 1
                    maxHeightReached = true
                }
            }
        }
    }
}
于 2020-10-31T15:30:27.570 回答