SwiftUIでChildView(子View)のFrameを取得
親ViewのFrame
はGeometryReader
を使うことで取得できますが、ChilViewでの取得方法がわからなかったので調べました。
GeometoryReander
とbackground
を利用する
background
ファンクションはView
へColor
を与えるために利用してると思います。
ここでbackground
ファンクションを良くみてみましょう。
実は引数はView
protocolに準拠しているものであればなんでもOKです。
@inlinable public func background<Background>(_ background: Background, alignment: Alignment = .center) -> some View where Background : View
Color
だってView
に準拠してます。
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension Color : View {
}
GeometoryReander
GeometoryReander
もView
に準拠したstructです。
GeometoryReanderを使うとこんな感じでGeometoryReanderを囲むView
のframe
を取得できます。
GeometryReader { proxy -> AnyView in
let rect = proxy.frame(in: .global)
print(rect
return AnyView(EmptyView())
}
ChildViewではどうするのか
今回はView
とfunc
の両方を使う方法を紹介します。
View
を使う方法
まずはView
を使う方法
ChildReader
を作りました。
struct ChildReader<Content>: View where Content: View {
var viewFrame: Binding<CGRect>
var content: Content
init (viewFrame: Binding<CGRect>, @ViewBuilder content: @escaping () -> Content) {
self.viewFrame = viewFrame
self.content = content()
}
var body: some View {
self.content
.background(
GeometryReader { proxy -> AnyView in
let rect = proxy.frame(in: .global)
if rect.integral != self.viewFrame.wrappedValue.integral {
DispatchQueue.main.async {
self.viewFrame.wrappedValue = rect
print(rect)
}
}
return AnyView(EmptyView())
}
)
}
}
取得したいView
をChildReader
で囲むとchildRect
にframe
が格納されます。
struct ContentView: View {
@State var childRect: CGRect = .zero
var body: some View {
ChildReader(viewFrame: $childRect) {
Text("Hello World!")
}
}
}
func
を使う方法
次にfunc
を使う方法を紹介します。ここではView
をextensionしています。
extension View {
func frame(frame: Binding<CGRect>) -> some View {
self.background(
GeometryReader { proxy -> AnyView in
let rect = proxy.frame(in: .global)
if rect.integral != frame.wrappedValue.integral {
DispatchQueue.main.async {
frame.wrappedValue = rect
print(rect)
}
}
return AnyView(EmptyView())
}
)
}
}
使い方はシンプルです。
struct ContentView: View {
@State var childRect: CGRect = .zero
var body: some View {
Text("Hello World!")
.frame(frame: $childRect)
}
}
それではみなさん快適なSwiftUIライフをお送りください!
SwiftUIとCloud Firestoreを簡単に連携できるサンプルプログラムを公開しています。
是非参考にどうぞ!
次の記事もオススメです。