Bagaimana cara mendapatkan ukuran dan posisi yang diberikan tampilan aktual di SwiftUI?
Pertanyaannya adalah bagaimana cara mendapatkan ukuran dan posisi yang ditampilkan sebenarnya dalam tampilan induk? Dengan kata lain, bagaimana cara mendapatkan Text("Foo")
ukuran sebenarnya pada kode SwiftUI di bawah ini?
GeometryReaderdapat digunakan untuk mendapatkan orang tua yang diusulkan size
dan inset area aman melalui safeAreaInsets
dan informasi ini didefinisikan di dalam GeometryProxy. Anda dapat melihat dari gambar di bawah ini, ukuran yang diusulkan untuk VStack
adalah 300
lebar dan 300
tinggi dan ukuran sebenarnya VStack
tidak diketahui.

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)
}
}
Jawaban
Ukuran Rendered Sebenarnya
Solusinya adalah mendapatkan ukuran aktual yang dirender melalui .background
pengubah dengan nested GeometryReader
. Informasi ukuran di dalam proxy geometri baru kemudian dapat disimpan dalam @State
variabel sementara yang ditentukan di Tampilan.
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)
}
}

Posisi Rendered Aktual
Posisi aktual yang diberikan untuk tampilan tersebut dapat dihitung menggunakan Anchor
dan anchorPreference
. Dengan menggunakan jangkar dan induk geometryProxy
, kita bisa dengan mudah mendapatkan .bound
informasi posisi tampilan target.
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)
}
}
