Come ottenere le dimensioni e la posizione effettive del rendering della vista in SwiftUI?
La domanda è: come ottenere le dimensioni e la posizione effettive del rendering visualizzato in una vista principale? In altre parole, come ottenere la Text("Foo")
dimensione effettiva nel codice SwiftUI di seguito?
GeometryReaderpuò essere utilizzato per inserire la proposta genitore size
e l'area sicura safeAreaInsets
e queste informazioni sono definite all'interno GeometryProxy. Puoi vedere dallo screenshot qui sotto, la dimensione proposta VStack
è 300
larghezza e 300
altezza e la dimensione effettiva per VStack
è sconosciuta.
struct FooView: View {
var body: some View {
GeometryReader { geometryProxy in
VStack {
Text("\(geometryProxy.size.height), \(geometryProxy.size.width)")
Text("Foo")
}
.background(Color.green)
}
.frame(width: 300, height: 300)
.background(Color.blue)
}
}
Risposte
Dimensioni effettive di rendering
La soluzione alternativa consiste nell'ottenere la dimensione effettiva del rendering tramite un .background
modificatore con un file nidificato GeometryReader
. Le informazioni sulla dimensione all'interno del nuovo proxy della geometria possono quindi essere memorizzate in una @State
variabile temporanea definita nella Vista.
struct FooSizePreferenceKey: PreferenceKey {
static let defaultValue = CGSize.zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct FooView: View {
@State private var fooSize: CGSize = .zero
var body: some View {
GeometryReader { geometryProxy in
VStack {
Text("\(self.fooSize.height), \(self.fooSize.width)")
Text("Foo")
.background(
GeometryReader { fooProxy in
Color
.green
.preference(key: FooSizePreferenceKey.self,
value: fooProxy.size)
.onPreferenceChange(FooSizePreferenceKey.self) { size in
self.fooSize = size
}
}
)
}
}
.frame(width: 300, height: 300)
.background(Color.blue)
}
}
Posizione reale resa
La posizione di rendering effettiva per la vista può essere calcolata utilizzando Anchor
e anchorPreference
. Usando l'ancora e il genitore geometryProxy
, possiamo facilmente ottenere le .bound
informazioni sulla posizione della vista di destinazione.
struct FooAnchorData: Equatable {
var anchor: Anchor<CGRect>? = nil
static func == (lhs: FooAnchorData, rhs: FooAnchorData) -> Bool {
return false
}
}
struct FooAnchorPreferenceKey: PreferenceKey {
static let defaultValue = FooAnchorData()
static func reduce(value: inout FooAnchorData, nextValue: () -> FooAnchorData) {
value.anchor = nextValue().anchor ?? value.anchor
}
}
struct FooView: View {
@State private var foo: CGPoint = .zero
var body: some View {
GeometryReader { geometryProxy in
VStack {
Text("\(self.foo.x), \(self.foo.y)")
Text("Foo")
.background(
GeometryReader { fooProxy in
Color
.green
.anchorPreference(key: FooAnchorPreferenceKey.self,
value: .bounds,
transform: {FooAnchorData(anchor: $0) })
.onPreferenceChange(FooAnchorPreferenceKey.self) { data in
self.foo = geometryProxy[data.anchor!].origin
}
}
)
}
}
.frame(width: 300, height: 300)
.background(Color.blue)
}
}