Swiftui 用于计算视图总高度的GeometryReader
我有一个固定宽度和高度的主视图,因为此视图将转换为PDF。接下来,我将在主视图中垂直堆叠一系列子视图。可能有更多的子视图可用,无法容纳在主视图中,因此我需要一种方法来确保我不超过主视图的总高度。例如,如果我的数组中有八个子视图,但只有三个子视图适合主视图,那么我需要停止在三个子视图之后添加子视图。其余的子视图将在新的主视图上重新开始该过程 我的问题是,如果我使用GeometryReader获取视图的高度,首先我必须添加它。但一旦添加视图,就太晚了,无法确定它是否超过了可用的总高度 下面显示了如何在添加每个视图时获取其高度。我知道,这没什么好谈的,但我被卡住了 更新: 我目前的策略是创建一个临时视图,在其中我可以添加子视图并返回一个只包含适合的子视图的数组Swiftui 用于计算视图总高度的GeometryReader,swiftui,geometryreader,Swiftui,Geometryreader,我有一个固定宽度和高度的主视图,因为此视图将转换为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)
}
}
您可以在一个位置获得总高度,如下所示:
VStack {
ForEach(tasks) { task in
TaskRowView(task: task)
}
}
.overlay(
GeometryReader { geo in
// geo.size.height // << move it here and get total height at once
})
VStack{
ForEach(tasks){task in
TaskRowView(任务:任务)
}
}
.叠加(
GeometryReader{geo-in
//geo.size.height/一种可能的解决方案是使用视图首选项
您可以计算项目的总高度,并在onPreferenceChange
中将其计数增加1(直到totalHeight
达到maxHeight
)
以下是完整的实施:
创建用于检索视图高度的自定义PreferenceKey
:
创建一个TaskRowView
(任意高度):
在视图中使用自定义首选项键
:
struct ContentView:View{
@国家私有变量计数=0
@国家私有变量totalHeight:CGFloat=0
@状态私有变量maxheightreach=false
设maxHeight:CGFloat=300
var body:一些观点{
VStack{
文本(“总高度:\(总高度)”)
VStack{
ForEach(0..<计数,id:\.self){
TaskRowView(索引:$0)
}
}
.background(ViewGeometry())
.onPreferenceChange(ViewHeightKey.self){
总高度=$0
打印(计数、总高度)
守卫!MaxheightElse{return}
如果$0<最大高度{
计数+=1
}否则{
计数-=1
maxheightreach=true
}
}
}
}
}
好的,使用您的解决方案,我可以得到主视图的总高度。使用我提供的代码,我可以得到每个子视图的高度。目标是只包含将适合主视图的子视图。那么,一旦达到限制,我如何停止添加视图?您所说的适合主视图是什么意思?在SwiftUI中er视图和它的内容一样大,所以你的所有子视图*都适合主视图。你是对的。但是,在我的例子中,高度是固定的,所以只有一定数量的子视图适合。我添加了一个图像来帮助澄清我的问题。谢谢!如果你已经定义了高度,那么你不需要计算任何东西,只需将高度应用到堆栈和剪辑内部,likeVStack{}.frame(高度:792).clipped()
-这将为您提供您所描述的内容。这可能会起作用,但当剪辑发生时,我如何知道我在阵列中的位置?保持运行总计的目的是为了将剩余的子视图添加到第二个主视图。顺便说一句,谢谢您-我感谢您的坚持。我不完全理解您的解决方案JU现在还没有,但它看起来很有前途。@squarehippo10这里有一个关于视图首选项的非常好的教程:
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)
}
}
}
struct TaskRowView: View {
let index: Int
var body: some View {
Text("\(index)")
.padding()
.background(Color.red)
}
}
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
}
}
}
}
}