GeometryReader는 그 자체로 View이며 상위뷰의 컨테이너의 크기를 통해서 하위뷰의 위치 및 크기를 선언하는데 사용한다.
container view의 크기 및 좌표공간에 대한 엑세스를 위한 proxy(대리인)이다.
GeometryReader로 뷰를 감싼 상위뷰 컨테이너의 frame,size,safeAreaInserts를 사용해서 하위뷰의 크기정보를 전달할 수 있다.
import SwiftUI
struct ContentView: View {
var body: some View {
// => iOS 14부터는 GeometryReader가 직접 안전 영역에 맞닿은 면에 한해 그 크기를 가져옵니다.
// 즉, bottom 은 다른 뷰에 접해있고 top 만 안전 영역에 닿아 있다면 bottom 은 0이고 top 만 알맞은 값을 가집니다.
VStack{
GeometryReader { geomotry in
Text("Geometry Reader")
.font(.largeTitle.bold())
.position(x: geomotry.size.width / 2, y: geomotry.safeAreaInsets.top) // 가로 중간 및 , 높이는 안전영역 위에
VStack{
Text("Size").bold()
Text("width : \(Int(geomotry.size.width))")
Text("Height : \(Int(geomotry.size.height))")
}.position(x: geomotry.size.width/2, y: geomotry.size.height / 2.5)
// VStack을 geomotry.size.width 중간에 위치 , y: geomory 높이/2.5에 위치
VStack {
Text("SafeAreaInsets").bold()
// 🔥
Text("top : \(Int(geomotry.safeAreaInsets.top))")
Text("bottom : \(Int(geomotry.safeAreaInsets.bottom))")
}
// 🔥
.position(x: geomotry.size.width / 2, y: geomotry.size.height / 1.4)
// VStack을 geomotry.size.width 중간에 위치 , y: geomory 높이/1.4에 위치
}
.font(.title)
.frame(height:500)
.border(.green,width: 5)
}
Rectangle()
}
}
enum CoordinateSpace {
case global // 화면 전체 영역(window bounds)을 기준으로 한 좌표 정보
case local // GeometryReader bounds 를 기준으로 한 좌표 정보
case named(AnyHashable) // 명시적으로 이름을 할당한 공간을 기준으로 한 좌표 정보
}
import SwiftUI
struct FrameView: View {
var body: some View {
HStack {
Rectangle().fill(Color.yellow)
.frame(width: 30)
VStack {
Rectangle().fill(Color.blue)
.frame(height: 200)
GeometryReader {
self.contents(geometry: $0)
.position(x: $0.size.width / 2, y: $0.size.height / 2) //상위 뷰인 VStack의 중간에 위치
}
.background(Color.green)
.border(Color.red, width: 4)
}
.coordinateSpace(name: "VStackCS") //이름 부여
}
.coordinateSpace(name: "HStackCS") //이름 부여
}
/// GeometryProxy.frame 다루기
func contents(geometry g: GeometryProxy) -> some View {
VStack {
// 🔥 GeometryReader 자신에 대한 bounds 값을 반환.(그래서 원점 (0,0) 반환)
Text("Local").bold()
Text(stringFormat(for: g.frame(in: .local).origin))
.padding(.bottom)
// 🔥
Text("Global").bold()
Text(stringFormat(for: g.frame(in: .global).origin))
.padding(.bottom)
Text("Named VStackCS").bold()
Text(stringFormat(for: g.frame(in: .named("VStackCS")).origin))
.padding(.bottom)
Text("Named HStackCS").bold()
Text(stringFormat(for: g.frame(in: .named("HStackCS")).origin))
.padding(.bottom)
}
}
/// CGPoint 를 가지고, String 으로 반환.
func stringFormat(for point: CGPoint) -> String {
String(format: "(x: %.f, y: %.f)", arguments: [point.x, point.y])
}
}