gpt4 book ai didi

swiftui - 根据其元素动态调整 GeometryReader 高度

转载 作者:行者123 更新时间:2023-12-04 11:07:46 32 4
gpt4 key购买 nike

我正在尝试做一些在我脑海中非常直接的事情。

我想要一个 VStack 的 subview 根据其内容动态更改其高度(下面示例中的 ProblematicView)。

它通常工作得很好,但在这种情况下, ProblematicView 包含一个 GeometryReader (以模拟多行的 HStack)。

但是, GeometryReader 贪婪地占用所有空间(如果您删除 GeometryReader 及其内容,则会发生预期的行为)。不幸的是,在父 View (下面示例中的 UmbrellaView)上,UmbrellaView VStack 将自身的 50% 分配给 ProblematicView,而不是显示 View 内容的最小尺寸。

我花了几个小时玩 min/ideal/maxHeight 框架参数,但无济于事。

我想要实现的目标可行吗?

我在底部添加了图片以在视觉上澄清。

struct UmbrellaView: View {
var body: some View {
VStack(spacing: 0) {
ProblematicView()
.background(Color.blue)

ScrollView(.vertical) {
Group {
Text("A little bit about this").font(.system(size: 20))
Divider()
}
Group {
Text("some").font(.system(size: 20))

Divider()
}
Group {
Text("group").font(.system(size: 20)).padding(.bottom)
Divider()
}
Group {
Text("content").font(.system(size: 20))
}
}

}
}
}


struct ProblematicView: View {

var body: some View {
let tags: [String] = ["content", "content 2 ", "content 3"]
var width = CGFloat.zero
var height = CGFloat.zero

return VStack(alignment: .center) {
Text("Some reasonnably long text that changes dynamically do can be any size").background(Color.red)
GeometryReader { g in
ZStack(alignment: .topLeading) {
ForEach(tags, id: \.self) { tag in
TagView(content: tag, color: .red, action: {})
.padding([.horizontal, .vertical], 4)
.alignmentGuide(.leading, computeValue: { d in
if (abs(width - d.width) > g.size.width)
{
width = 0
height -= d.height
}
let result = width
if tag == tags.last! {
width = 0 //last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if tag == tags.last! {
height = 0 // last item
}
return result
})
}
}.background(Color.green)
}.background(Color.blue)
}.background(Color.gray)
}
}

struct TagView: View {
let content: String
let color: Color
let action: () -> Void?

var body: some View {
HStack {
Text(content).padding(EdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5))
Button(action: {}) {
Image(systemName: "xmark.circle").foregroundColor(Color.gray)
}.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 7))
}
.background(color)
.cornerRadius(8.0)
}
}

struct ProblematicView_Previews: PreviewProvider {
static var previews: some View {
return ProblematicView()
}
}


struct UmbrellaView_Previews: PreviewProvider {
static var previews: some View {
return UmbrellaView()
}
}

ProblematicView Preview

UmbrellaView Preview

最佳答案

由于 GeometryReader 本质上的“鸡蛋”问题主题问题的解决方案仅在运行时才有可能,因为 1) 初始高度未知 2) 它需要根据所有可用的外部尺寸计算内部尺寸 3) 它需要将外部尺寸紧缩到计算出的内部尺寸。

所以这是可能的方法(在你的代码中有一些额外的修复)

preview run-time run-time2

1) 预览 2-3) 运行时

代码:

struct ProblematicView: View {

@State private var totalHeight = CGFloat(100) // no matter - just for static Preview !!
@State private var tags: [String] = ["content", "content 2 ", "content 3", "content 4", "content 5"]

var body: some View {
var width = CGFloat.zero
var height = CGFloat.zero

return VStack {
Text("Some reasonnably long text that changes dynamically do can be any size").background(Color.red)
VStack { // << external container
GeometryReader { g in
ZStack(alignment: .topLeading) { // internal container
ForEach(self.tags, id: \.self) { tag in
TagView(content: tag, color: .red, action: {
// self.tags.removeLast() // << just for testing
})
.padding([.horizontal, .vertical], 4)
.alignmentGuide(.leading, computeValue: { d in
if (abs(width - d.width) > g.size.width)
{
width = 0
height -= d.height
}
let result = width
if tag == self.tags.last! {
width = 0 //last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if tag == self.tags.last! {
height = 0 // last item
}
return result
})
}
}.background(Color.green)
.background(GeometryReader {gp -> Color in
DispatchQueue.main.async {
// update on next cycle with calculated height of ZStack !!!
self.totalHeight = gp.size.height
}
return Color.clear
})
}.background(Color.blue)
}.frame(height: totalHeight)
}.background(Color.gray)
}
}

struct TagView: View {
let content: String
let color: Color
let action: (() -> Void)?

var body: some View {
HStack {
Text(content).padding(EdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5))
Button(action: action ?? {}) {
Image(systemName: "xmark.circle").foregroundColor(Color.gray)
}.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 7))
}
.background(color)
.cornerRadius(8.0)
}
}

关于swiftui - 根据其元素动态调整 GeometryReader 高度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61311007/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com