Wie erhalte ich die tatsächliche Größe und Position der gerenderten Ansicht in SwiftUI?
Die Frage ist, wie die tatsächlich angezeigte gerenderte Größe und Position in einer übergeordneten Ansicht ermittelt werden kann. Mit anderen Worten, wie erhält man die tatsächliche Text("Foo")
Größe im SwiftUI-Code unten?
GeometryReaderkann verwendet werden, um den übergeordneten vorgeschlagenen size
und sicheren Bereich einzufügen, safeAreaInsets
und diese Informationen werden im Inneren definiert GeometryProxy. Sie können aus dem Screenshot unten, um die vorgeschlagene Größe VStack
ist 300
Breite und 300
Höhe und die tatsächliche Größe für die VStack
ist nicht bekannt.
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)
}
}
Antworten
Tatsächliche gerenderte Größe
Die Problemumgehung besteht darin, die tatsächlich gerenderte Größe über einen .background
Modifikator mit einem verschachtelten zu erhalten GeometryReader
. Die Größeninformationen im neuen Geometrie-Proxy können dann in einer temporären @State
Variablen gespeichert werden, die in der Ansicht definiert ist.
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)
}
}
Tatsächliche gerenderte Position
Die tatsächlich gerenderte Position für die Ansicht kann mit Anchor
und berechnet werden anchorPreference
. Mit dem Anker und dem übergeordneten geometryProxy
Element können wir leicht die Positionsinformationen .bound
der Zielansicht abrufen.
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)
}
}