我在 VStack
中有两个 Text
组件,我使用 GeometryReader
来匹配它们的宽度。
问题是,如果我在将 frame
设置为内容较短的 Text
后应用 padding
,我会遇到无限循环。
我想了解为什么会发生这种情况。我的期望是它应该只采用较大的宽度,然后对其应用填充。
import SwiftUI
struct ContentView: View {
@State private var containerWidth: CGFloat?
var body: some View {
VStack(alignment: .center) {
Text("Shorter Text")
.frame(width: containerWidth, alignment: .center)
.background { Color.green }
// this is `padding` is causing an infinite loop
.padding(.leading, 5)
Text("Really really long text")
.background {
Color.yellow
}
}
.background {
Color.red
}
.readSize { size in
containerWidth = size.width
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension View {
func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self, perform: onChange)
}
}
private struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}
我尝试切换padding
的应用程序。这可以防止宽度计算的无限递归,但不会添加填充。
最佳答案
让我们来分析一下它挂起的原因:
- 首先第一个文本宽度 = nil,这意味着它有自己的宽度
- 'readSize' 设置宽度,强制 VStack 调整大小
- VStack 已调整大小,因此“readSize”再次设置宽度
这就是我要做的:
struct ContentView: View {
@State private var containerWidth: CGFloat?
var body: some View {
VStack {
Text("Shorter Text")
.readSize { storeWidth($0.width) }
.frame(width: containerWidth)
.background { Color.green }
Text("Really really long text")
.readSize { storeWidth($0.width) }
.frame(width: containerWidth)
.background { Color.yellow }
}
.background { Color.red }
}
func storeWidth(_ value: CGFloat) {
containerWidth = max(value, containerWidth ?? -.infinity)
}
}
像这样,“readSize”将执行一次,因为文本不会改变其宽度。修饰符的顺序很重要,这就是为什么将frame(width:)放在'readSize'之后
关于swift - 使用 GeometryReader 和 Padding 时的无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75527469/