[SwiftUI] offset position 의 layout 단계

레이아웃 단계별로 그림과 함께 살펴봅시다

naljin
13 min readSep 20, 2022

들어가기 전에

저번 시간에 offset 과 position 의 결과 차이를 이해하기 위해서는 SwiftUI 가 뷰의 크기를 결정하고 배치하는 원리를 알아야한다고 했습니다.

Text("눈물의 layout")
.background(Color.red)
.offset(x: 100, y: 100)
.background(Color.blue)
Text("눈물의 layout")
.background(Color.red)
.position(x: 100, y: 100)
.background(Color.blue)

이를 위해 WWDC 에서 설명하는 SwiftUI 의 layout 3 단계를 먼저 살펴봤는데요, 이 내용만 해도 꽤 길다보니 offset 과 position 의 layout 단계까지 한 포스트에서 담기엔 족굼 오바더라구여?

그래서 글을 나눴습니다. 두둥.

여기서는 저번 포스트에서 알아본 “SwiftUI 의 layout 동작 방식”을 바탕으로 offset 과 position 의 동작을 살펴보겠습니다.

이전 글에서 이해한 내용을 바탕으로 내용이 전개되니, 해당 포스트를 읽지 않으신 분들은 꼭 보고 와주세요!

이전 포스트

offset

지정된 수평 및 수직 거리만큼 이 view 를 오프셋합니다.

이제 아래 그림의 결과가 어떻게 해서 나오는건지 살펴보겠습니다.

먼저 Root View 에서 자식에게 사용 가능한 Size 를 제안합니다.

Background 부터 Text 까지의 view hierarchy 에는 padding 이나 frame 같은 상위 뷰로부터 제안받은 size 를 변경할만한 modifier 가 없기 때문에, 해당 사이즈가 쭉 하위 뷰에게 전달 됩니다.

이제 Text 는 자신이 원하는 크기를 상위 뷰에 보고합니다. (String 길이만큼)

Background View 는 Child 의 사이즈를 동일하게 사용하고, Child 를 자신의 가운데 배치합니다.

Background View 의 secondary child 인 Color View 도 부모 (Background view) 로부터 크기를 제안받습니다 ( == Text 에서 전달받은 크기).

Color View 는 레이아웃 중립이면서, child 가 따로 없기 때문에 부모로부터 제안 받은 사이즈를 사용합니다.

Color View 의 사이즈가 정해졌으니, 이제 Background View 는 자신의 가운데 Color 뷰를 배치합니다.

Background View 는 Offset View 에게 자신의 사이즈를 알립니다.

Offset 도 레이아웃 중립이기 때문에, Child 로부터 받은 x, y 크기를 사용할 것입니다. 그리고 child 를 자신의 좌표 공간내에 offset 만큼 떨어트려 배치합니다. 다만 여기서 주의할 점은 offset modifier 을 사용하더라도 view 의 original dimension 은 변하지 않는다는 것입니다.

Child의 배치를 마친 Offset View 는 Background View 에게 자신이 사용할 사이즈 (x, y) 를 알립니다.

Background View 도 자신의 크기를 Child 에게 보고 받은 x, y 만큼 사용할 것입니다. 그리고 Offset View 를 자신의 가운데 배치합니다.

Background View 는 다른 Child 인 Color View 에도 Size 를 제안합니다.

Color 뷰는 부모로부터 제안받은 사이즈를 사용합니다.

그리고 Background View 는 자신의 가운데 Color View 를 배치합니다. (가운데라고 해봤자 두 View 의 size 가 같기 때문에, 결국 같은 좌표에 위치하게 됩니다).

Child 의 위치 조정을 마친 Background View 는 이제 Root View 에게 사용할 size 를 보고합니다.

Root View 는 자신의 좌표 공간 내에서 가운데에 Background View 를 배치합니다.

Position

이 뷰의 중심을 부모 좌표 공간의 지정된 좌표에 배치합니다.

아래 그림의 결과가 어떻게 해서 나온건지 방금과 같은 방식으로 살펴보겠습니다.

전과 마찬가지로 RootView 는 available space 를 child 에게 제안합니다.

Background View 는 레이아웃 중립입니다. 따라서 child 인 Position View 가 사용할 size 를 물어보고 이와 동일한 size 를 사용할 것입니다.

Position View 는 available 한 space 를 모두 사용하는 View 입니다.

모든 가용 영역을 사용하기로 결정한 Position View는 해당 size 만큼 다시 child 에게 제안합니다.

아까 말했듯 Background View 는 레이아웃 중립입니다. 따라서 child 인 Text View 가 사용할 size 를 물어보고 이와 동일한 size 를 사용할 것입니다.

Text 는 자신이 원하는 크기를 말합니다 (String 길이만큼).

Background View 는 Child 의 사이즈를 동일하게 사용하고, Child 를 자신의 가운데 배치합니다.

Background View 의 secondary child 인 Color View 도
부모 (Background view) 로부터 크기를 제안받습니다 ( == Text 에서 전달받은 크기).

Color View 는 레이아웃 중립이면서, child 가 따로 없기 때문에 부모로부터 제안 받은 사이즈를 사용합니다.

Color View 의 사이즈가 정해졌으니, 이제 Background View 는 자신의 가운데 Color 뷰를 배치합니다.

이제 Background View 는 Position View 에게 자신의 사이즈를 알립니다.

아까 말했듯 Position View 는 available 한 space 를 모두 사용합니다.
그리고 자신 좌표 공간 내의 지정된 좌표에 child 뷰의 중심을 배치합니다

Child의 배치를 마친 Position View 는 Background View 에게 자신이 사용할 사이즈 (전체 사용 가능 영역) 를 알립니다.

Background View 도 자신의 크기를 Child 에게 보고 받은 사이즈만큼 사용할 것입니다. 그리고 Position View 를 자신의 가운데 배치합니다 (가운데라고 해봤자 두 View 의 size 가 같기 때문에, 결국 같은 좌표에 위치하게 됩니다).

Background View 는 다른 Child 인 Color View 에도 Size 를 제안합니다.

Color 는 부모로부터 제안받은 사이즈를 사용합니다.

그리고 Background View 는 자신의 가운데 Color View 를 배치합니다.

Child 의 위치 조정을 마친 Background View 는 이제 Root View 에게 사용할 size 를 보고합니다.

Root View 는 자신의 좌표 공간 내에서 가운데에 Background View 를 배치합니다.

상대 위치? 절대 위치?

Absolute positioning for SwiftUI views 에서 offset 은 relative position 을, position 은 absolute position 을 지정하는데 사용한다고 말합니다.

여기서 상대와 절대의 의미가 무엇인지, 아래의 예시를 통해 짐작해보겠습니다.

offset — relative positions (상대)

Offset View 는 자신이 위치할 곳에서 (x, y) 떨어진 곳에 자식을 위치시킵니다.

여기서 “자신이 위치할 곳” 은 Parent 의 alignment 정책 등에 따라 달라집니다. (bottom Trailing, center, top 등..)

👉🏻 따라서 이를 두고 “상대적” 이라고 하는게 아닐까요? 🤔

position — absolute positions (절대)

Position View 는 제안 받은 전체 공간을 기준으로, (0,0) 에서(x, y) 떨어진 곳에 자식의 center 를 위치시킵니다.

Position View 는 Parent 에서 제안받은 Size 를 모두 사용하기 때문에 Parent 와 사이즈가 딱 맞습니다. 따라서 Parent 의 alignment 정책 등에 따라 위치가 달라지지 않습니다.

👉🏻 따라서 이를 두고 “절대적” 이라고 하는게 아닐까요..? 🤔

Bonus — background(_:ignoresSafeAreaEdges:)

마지막으로 background(_:ignoresSafeAreaEdges:) 에 대해 한가지 짚고 끝내도록 하겠습니다.

Quiz 1.

아래 코드를 실행했을 때 둘 중 어떤 결과가 나올 거 같나여?

저는 아래와 같이 생각했는데요,

현실은 safe area 넘어서까지 background 색상이 채워지는 결과가 나타났습니다.

Quiz 2.

비슷한 다른 코드를 또 봐볼게여. 어떤 결과가 나올거 같나요?

여기서도 저는 아래와 같이 빨간 색상이 Text 만큼의 영역을 차지할거라고 생각했는데요,

현실은 Text 높이보다 크게 safe area 넘어서까지 background 색상 채워지는 것을 확인할 수 있었습니다.

두 케이스를 합쳐보면? ㅎㅎ…

뭔가~ safe area 와 관련이 있을거 같다~ 라는 생각은 어렴풋이 드는데요!

정확한 이유는 background(_:ignoresSafeAreaEdges:) 에서
두번째 인자에 safe area 를 무시할 edges 를 지정할 수 있는데 default value 가 .all 이기 때문입니다.

따라서 모든 safe area 를 고려하고 싶다면 해당 영역에 empty set 을 넣습니다.

마무리

ㅋㅋㅋ,ㅋ,ㅋ, ㅋ,, 피피티 숫자가 이게 맞는거예여,,?

길고…힘든 시간이었던만큼 제대로 이해한게 맞길 바라며..? 아닌거 같다면 언제든 댓글 기다리고 있슴니다 🫠 🫠🫠

그럼.. 20000!

출처

--

--

Responses (1)