¿Cómo obtener el tamaño y la posición reales de la vista en SwiftUI?
La pregunta es cómo obtener el tamaño y la posición reales visualizados en una vista principal. En otras palabras, ¿cómo obtener el Text("Foo")
tamaño real en el código SwiftUI a continuación?
GeometryReaderse puede utilizar para size
insertar la propuesta principal y el área segura mediante safeAreaInsets
y esta información se define en el interior GeometryProxy. Puede ver en la captura de pantalla a continuación que el tamaño propuesto VStack
es 300
ancho y 300
alto y VStack
se desconoce el tamaño real .
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)
}
}
Respuestas
Tamaño real renderizado
La solución es obtener el tamaño real renderizado mediante un .background
modificador con un archivo GeometryReader
. La información de tamaño dentro del nuevo proxy de geometría se puede almacenar en una @State
variable temporal definida en la 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)
}
}
Posición real renderizada
La posición real renderizada para la vista se puede calcular usando Anchor
y anchorPreference
. Usando el ancla y el padre geometryProxy
, podemos obtener fácilmente la .bound
información de posición de la vista de destino.
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)
}
}