SwiftUI GeometryReader, ebeveyninin durumunu güncelleyemedi
Dün şu gönderiye rastladım: SwiftUI'de GeometryReader nedir? ve davranışını merak ediyordum GeometryReader, bu yüzden bazı deneyler yaptım ve aşağıdaki yazıyı okuduktan sonra yaptığım şey:
import SwiftUI
import PlaygroundSupport
/* ------- Approach 1 ------- */
struct ViewGettingSize: View {
@Binding var size: CGSize
func makeView(with geometry: GeometryProxy) -> some View {
// ⭐️ Try to update @Binding var `size`,
// but SwiftUI ignores this assignment, why?
// @Binding var `size` is NOT updated.
self.size = geometry.size
print(geometry.size) // (158.5, 45.5)
print(self.size) // (50, 50)
return Color.pink
}
var body: some View {
GeometryReader { geo in
self.makeView(with: geo) // Color.pink
}
}
}
/* ------- Approach 2 ------- */
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct ViewSettingSizePreference: View {
func makeView(with geometry: GeometryProxy) -> some View {
print(geometry.size) // (158.5, 45.5)
return Color.orange
.preference(key: SizePreferenceKey.self, value: geometry.size)
}
var body: some View {
GeometryReader { geo in
self.makeView(with: geo) // Color.orange
}
}
}
/* ------- Test These Approaches ------- */
let text = Text("some text").font(.largeTitle)
// live view
struct ContentView: View {
@State private var size = CGSize(50, 50)
@State private var size2 = CGSize(50, 50)
var body: some View {
VStack {
Group {
/* ------- Approach 1 ------- */
text
// ⭐️ this one doesn't work.
.background(ViewGettingSize(size: $size))
Color.blue
// ⭐️ `size` is still (50,50)
.frame(width: self.size.width, height: self.size.height)
/* ------- Approach 2 ------- */
text
// ⭐️ this one works.
.background(ViewSettingSizePreference())
.onPreferenceChange(SizePreferenceKey.self) { (size) in
print(size) // (158.5, 45.5)
self.size2 = size // ⭐️ `size2` updated successfully.
print(self.size2) // (158.5, 45.5)
}
Color.purple
.frame(width: self.size2.width, height: self.size2.height)
}// Group
.border(Color.black)
}// VStack (container)
.padding()
.background(Color.gray)
}
}
PlaygroundPage.current.setLiveView(ContentView())
Sonuç:
Yukarıdan, iki yaklaşım kullandım ContentViewve @Statedeğişkenlerini güncelleyerek güncellemeye çalıştım , ikinci yaklaşım başarılı olsa da, ilki başarısız oldu, neden başarısız olduğunu bilen var mı? Teşekkürler.
Yanıtlar
// but SwiftUI ignores this assignment, why?
Çünkü işleme döngüsü üretecektir (değişen durum yenilemeyi başlatır, bu durum değişir vb.) Ve SwiftUI oluşturma motoru bu tür güncellemeleri bırakacak kadar akıllıdır.
Böyle bir güncellemeyi sonraki olay döngüsü için ertelemeniz gerekir, örneğin
func makeView(with geometry: GeometryProxy) -> some View {
DispatchQueue.main.async {
self.size = geometry.size
}
print(geometry.size) // (158.5, 45.5)
print(self.size) // (50, 50)
return Color.pink
}
Örneğin, bu yaklaşıma bakın. içindehttps://stackoverflow.com/a/60214735/12299030