본문 바로가기
🍎 iOS/SwiftUI

[SwiftUI] GeometryReader란? (feat. GeometryProxy,CoordinateSpace)

by Fomagran 💻 2022. 4. 4.
728x90
반응형

 

안녕하세요 Foma 💻 입니다!

 

오늘은 SwitUI를 이용해서 Layout을 잡을 때 아주 유용하게 사용되는 GeometryReader에 대해서 알아보려고 합니다.

 

바로 시작할게요~


GeometryReader란?

 

이름을 직역하면 Geometry는 기하학을 나타내니깐, 기하학적인 무언가를 읽는 것이라고 해석할 수 있는데요.

 

 

공식 문서에도 이름을 직역한 것과 비슷하게 "컨텐츠의 크기와 위치를 함수로 나타내는 컨테이너 뷰야!" 라고 소개합니다.

 

 

GeometryReader를 초기화 하는 방법은 아래와 같이 컨텐츠를 만드는데 GeometryProxy를 이용해서 만듭니다.

 


GeometryProxy란?

 

그렇다면 GeometryProxy는 무엇일까요?

 

우선 Proxy의 뜻은 무엇인가를 대신 한다는 의미를 나타냅니다.

 

고로 Geometry + Proxy는 기하학적인 정보를 대신 나타내주는 무엇이라고 해석할 수 있겠네요.

 

 

GeometryReader의 공식 문서에서 아래로 내리면 See Also로 GeometryProxy가 있습니다.

 

 

공식 문서에는 "컨테이너 뷰의 좌표나 크기를 접근할 수 있는 것" 이라고 소개합니다.

 

 

즉, GeometryReader는 기하학적인 정보를 가지고 있는 컨테이너 뷰 자체이고 해당 정보를 얻어내기 위해선 GeometrryProxy를 이용해야 하는 것이죠.

 

GeometryProxy를 통해서 접근할 수 있는 값은 아래와 같이 frame(in:), size, safeAreaInsets가 있습니다.

 

보통 frame(in:) 메서드를 이용하여 좌표값을 구하고, size를 이용하여 크기를, safeAreaInsets를 통해 컨테이너 뷰의 safe area의 가장 자리를 구할 수 있습니다.

 


직접 사용해보기

 

위에서 이론을 살펴 보았으니 실제로 어떻게 쓰이는지 알아보겠습니다.

 

아래와 같이 VStack과 HStack과 Spacer()를 이용하여 GeometryReaderDetailView를 배치해 보겠습니다.

 

GeometryReaderView

 

struct GeometryReaderView: View {
    var body: some View {
        VStack {
            Spacer()
            HStack {
            GeometryReaderDetailView()
                Spacer()
            }
        }
    }
}

 

GeometryReaderDetailView

 

struct GeometryReaderDetailView: View {
    var body: some View {
       Rectangle()
    }
}

 

이렇게 배치하면 아래와 같이 화면에 나타나게 됩니다.

 

이와 같이 나타나는 이유는 SwiftUI에선 Content를 파악하고 해당 크기를 예측하여 설정하기 때문입니다.

 

 

위와 같은 화면에서 검정색 사각형의 크기를 어떻게 구할 수 있을까요?

 

바로 여기서 GeometryReader를 사용하면 됩니다.


Size

 

아래와 같이 크기를 알아내고 싶은 View를 GeometryReader로 감싸줍니다.

 

struct GeometryReaderView: View {
    var body: some View {
        VStack {
            Spacer()
            HStack {
                GeometryReader { proxy in
                    GeometryReaderDetailView()
                        .onAppear {
                            print(proxy.size)
                        }
                }
                Spacer()
            }
        }
    }
}

 

아래와 같이 GeometryReaderDetailView의 width와 height를 알아낼 수 있습니다.

 


Frame

 

이제 크기를 알아냈으니 해당 컨테이너가 어디에 위치해 있는지 좌표를 구해보도록 하겠습니다.

 

좌표를 구하기 위해선 proxy의 frame(in:)을 이용해야 하는데요.

 

총 3가지 coordinatespace가 존재합니다.


CoordinateSpace란?

 

공식 문서엔 "뷰의 좌표에 이름을 정해서 다른 코드에서 작동하도록 하는 메서드" 라고 소개합니다.

 

 

즉, 뷰의 위치를 '어느 기준으로 바라볼 것인가'를 정하는 메서드입니다.

 

이미 정해진 기준이 global,local이 존재하며 원하는 뷰를 named를 통해서 이름 붙일 수 있습니다.

 

 

1. global

 

global은 전체 화면에서 바라보았을 때의 위치를 의미합니다.

 

2. local

 

현재 직접적으로 감싸져 있는 뷰에서 바라보았을 때의 위치를 의미합니다.

 

3. named

 

원하는 뷰에 이름을 붙이고 해당 뷰에서 바라보았을 때 위치를 의미합니다.


다시 GeometryProxy의 frame(in:)으로 돌아와서 설명하면,

 

GeometryReaderDetail뷰의 위치를 어느 뷰 기준으로 바라볼 것인지를 정하는 것인데요.

 

아래와 같이 global - 뷰 전체에서 위치 , local - GeotryReader에서의 위치 , named("HStack") HStack에서 위치를 출력해 보겠습니다.

 

 var body: some View {
        VStack {
            Spacer()
            HStack {
                Spacer()
                GeometryReader { proxy in
                    GeometryReaderDetailView()
                        .onAppear {
                            print(proxy.frame(in: .global))
                            print(proxy.frame(in: .local))
                            print(proxy.frame(in: .named("HStack")))
                        }
                }
            }
            .coordinateSpace(name: "HStack")
        }
    }

 

 

 

아래와 같이 출력되게 됩니다.

 


SafeAreaInsets

 

GeometryProxy에선 해당 컨테이너 뷰의 safeareaInsets의 정보도 알아낼 수 있는데요.

 

 

아래와 같이 View를 배치하고 safeAreaInsets를 출력하면

 

  var body: some View {
        VStack {
            HStack {
                GeometryReader { proxy in
                    GeometryReaderDetailView()
                        .onAppear {
                            print(proxy.safeAreaInsets)
                        }
                }
            }
        }
        
    }

 

 

 

위에선 safearea가 위쪽과 아래쪽만 적용이 되어 있으니 top,bottom의 값만 출력되는 것을 볼 수 있습니다.

 

 

만약 VStack에 safearea를 무시하도록 하게 되면

 

    VStack {
            HStack {
                GeometryReader { proxy in
                    GeometryReaderDetailView()
                        .onAppear {
                            print(proxy.safeAreaInsets)
                        }
                }
            }
        }
        .ignoresSafeArea(.all)

 

아래와 같이 safearea가 위쪽과 아래쪽이 무시되게 됩니다.

 

 

고로 출력되는 값도 top과 bottom이 0으로 변한 것을 볼 수 있습니다.

 


오늘은 이렇게 GeometryReader에 대해서 알아보았는데요.

 

이것을 통해서 좀 더 세부적이고 정교한 레이아웃 작업을 SwiftUI에서 할 수 있겠다라는 생각이 들었습니다.

 

혹시라도 틀린 점이 있거나 지적해주실 부분이 있다면 댓글로 알려주세요!


Reference

 

 

Apple Developer Documentation

 

developer.apple.com

 

 

Understanding frames and coordinates inside GeometryReader - a free Hacking with iOS: SwiftUI Edition tutorial

Was this page useful? Let us know! 1 2 3 4 5

www.hackingwithswift.com

 

728x90
반응형

댓글