类似 SwiftUI FlowLayout 的视图溢出 VStack 中的其他视图
SwiftUI FlowLayout-like View overflowing over other view in VStack
我在 Whosebug 上发现了一些关于创建灵活布局 (FlowLayout) 的问题,比如通常显示标签,根据文本使用不同的按钮宽度,必要时在多行上显示。
代码是这样的:
@State var buttonStrings:[String]=[String]()
init()
{
self.buttonStrings=createStrings()
}
private func item(for text: String) -> some View {
Button(action:{doSomething()})
{
Text(text)
}
}
private func generateContent(in g: GeometryProxy) -> some View {
var width = CGFloat.zero
var height = CGFloat.zero
return ZStack(alignment: .topLeading) {
ForEach(self.buttonStrings, id: \.self) { string in
self.item(for: string)
.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 string == self.buttonStrings.last! {
width = 0 //last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if string == self.buttonStrings.last! {
height = 0 // last item
}
return result
})
}
}
}
它有效,但是当这种视图在 VStack 内并且另一个视图紧随其后时,它会垂直溢出到另一个视图上(或者根据布局配置和 Stacks 的存在将其驱逐到底部) .
如何避免这种情况并且灵活的视图不会溢出或太大?
事实上,它里面的视图被置换了,这导致了这个问题。
使用该代码的正确方法是
struct FlowLayoutLikeView:View
{
var geometry:GeometryProxy
@State var buttonStrings:[String]=[String]()
init(geometry:GeometryProxy,....)
{
self.geometry=geometry
...
...
}
var body: some View {
self.generateContent(in: geometry)
}
private func item(for text: String) -> some View {
Button(action:{doSomething()})
{
Text(text)
}
}
private func generateContent(in g: GeometryProxy) -> some View {
var width = CGFloat.zero
var height = CGFloat.zero
return ZStack(alignment: .topLeading) {
ForEach(self.buttonStrings, id: \.self) { string in
self.item(for: string)
.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 string == self.buttonStrings.last! {
width = 0 //last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if string == self.buttonStrings.last! {
height = 0 // last item
}
return result
})
}
}
}
包含的视图必须像
var body: some View {
VStack //this does the trick, do not remove
{
GeometryReader { geometry in
VStack //this also does the trick, do not remove
{
FlowLayoutLikeView(geometry)
AnotherView() //this will be fine, it will be placed below the FlowLayoutLikeView, no overlapping, overflowing or ousting
}
}
}
}
我在 Whosebug 上发现了一些关于创建灵活布局 (FlowLayout) 的问题,比如通常显示标签,根据文本使用不同的按钮宽度,必要时在多行上显示。
代码是这样的:
@State var buttonStrings:[String]=[String]()
init()
{
self.buttonStrings=createStrings()
}
private func item(for text: String) -> some View {
Button(action:{doSomething()})
{
Text(text)
}
}
private func generateContent(in g: GeometryProxy) -> some View {
var width = CGFloat.zero
var height = CGFloat.zero
return ZStack(alignment: .topLeading) {
ForEach(self.buttonStrings, id: \.self) { string in
self.item(for: string)
.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 string == self.buttonStrings.last! {
width = 0 //last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if string == self.buttonStrings.last! {
height = 0 // last item
}
return result
})
}
}
}
它有效,但是当这种视图在 VStack 内并且另一个视图紧随其后时,它会垂直溢出到另一个视图上(或者根据布局配置和 Stacks 的存在将其驱逐到底部) .
如何避免这种情况并且灵活的视图不会溢出或太大? 事实上,它里面的视图被置换了,这导致了这个问题。
使用该代码的正确方法是
struct FlowLayoutLikeView:View
{
var geometry:GeometryProxy
@State var buttonStrings:[String]=[String]()
init(geometry:GeometryProxy,....)
{
self.geometry=geometry
...
...
}
var body: some View {
self.generateContent(in: geometry)
}
private func item(for text: String) -> some View {
Button(action:{doSomething()})
{
Text(text)
}
}
private func generateContent(in g: GeometryProxy) -> some View {
var width = CGFloat.zero
var height = CGFloat.zero
return ZStack(alignment: .topLeading) {
ForEach(self.buttonStrings, id: \.self) { string in
self.item(for: string)
.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 string == self.buttonStrings.last! {
width = 0 //last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if string == self.buttonStrings.last! {
height = 0 // last item
}
return result
})
}
}
}
包含的视图必须像
var body: some View {
VStack //this does the trick, do not remove
{
GeometryReader { geometry in
VStack //this also does the trick, do not remove
{
FlowLayoutLikeView(geometry)
AnotherView() //this will be fine, it will be placed below the FlowLayoutLikeView, no overlapping, overflowing or ousting
}
}
}
}