Я хотел бы отобразить Hstacks слова и его CGSize.width. Но это работает только для первого слова в массиве, все следующие слова отображаются с этим первым значением... Может ли кто-нибудь сказать мне, почему это не работает? Спасибо.
import SwiftUI
struct SizePreferenceKey: PreferenceKey {
typealias Value = CGSize
static var defaultValue: Value = .zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value = nextValue()
}
}
struct ContentView: View {
@State var childSize: CGSize = .zero
@State var width: CGFloat = 0
let words = ["this ","is ","just ","an ","example."]
var body: some View {
ForEach (0..<words.count) { index in
HStack{
Text("\(self.words[index])")
.background(
GeometryReader { proxy in
Color.red
.preference(key: SizePreferenceKey.self, value: proxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self) { preferences in
self.childSize = preferences
self.width = self.childSize.width
}
Text("\(self.width)")
}
.font(.largeTitle)
}
.frame(width: 600, height: 800)
}
}





Вы не можете использовать одну переменную состояния для всех строк, потому что ее значение переопределяется во время макета, и они отображаются последними во время рендеринга.
Вы должны использовать массив одинаковой длины для хранения ширины каждого слова.
Вот решение. Протестировано с Xcode 12.1/iOS 14.1
struct ContentView: View {
@State private var width: [CGFloat] // << declare only
let words = ["this ","is ","just ","an ","example."]
init() {
// create state array for width same count as words
_width = State(initialValue: Array(repeating: CGFloat.zero, count: words.count))
}
var body: some View {
VStack {
ForEach (0..<words.count) { index in
HStack{
Text("\(self.words[index])")
.background(
GeometryReader { proxy in
Color.red
.preference(key: SizePreferenceKey.self, value: proxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self) { preferences in
// store corresponding width for later use
self.width[index] = preferences.width
}
Text("\(self.width[index])")
}
.font(.largeTitle)
}
// .frame(width: 600, height: 800) // disabled for testing
}
}
}