SWIFT개발

근본으로 돌아가자(3)-View Layout

2료일 2024. 2. 26. 14:09

정말정말정말 오랜만에 글을쓰는 것 같다... 아카데미가 끝난 이후 개인프로젝트를 몇개 하고 상하이 여행도 갔다오고 게임도 하고... 쫌 놀았다.. 정신줄 놓고 있었는데 한 동아리 면접을 보러 갔다가 정신을 차리게 되었다! 이전까지는 나정도면...못하진 않지? 했다가 그냥 탈탈 탈곡기마냥 털렸다....정말정말정말 부끄러웠던 순간이였다...... 그래서 다시 근본으로 돌아가자!

https://developer.apple.com/videos/play/wwdc2019/237/

 

Building Custom Views with SwiftUI - WWDC19 - Videos - Apple Developer

Learn how to build custom views and controls in SwiftUI with advanced composition, layout, graphics, and animation. See a demo of a high...

developer.apple.com

이미 19년도에 나와 많은 능력자들이 정리를 해주셨다. 하지만 난 내방식대로 먼저 공부를 해볼까한다. 기초부터! 

Struct ContentView: View {
  var body: some View {
	Text("BLACKPINK IN YOUR AREA")
   }
  }

이렇게 있으면 맨아래 Text가 있을 거고 body부분과 항상 동일한영역을 가지는ContentView가 그 위에 있을 것이다. 그리고!! 그 위에 루트뷰가 존재한다.(Safe area 제외의 영역)!

여기서 ContentView(뷰들의 최상위 Layer)는 Body영역에 의해 결정되는 항상 layout neutral이라고 말씀하셨다. 

자 저게 동영상에서 겹쳐지는 과정이다. 동일하게 동작하기에 레이아웃의 목적을 위해 동일한 뷰로 취급할 수 있다는 뜻이다.

Layout Process

1. Parent뷰가 Child에게 크기를 제안한다

2. Child는 Parent의 크기제안을 고려해서 자신의 크기를 결정한다(하지만 강요는 못한다.)

3. Parent는 Child의 결정을 존중 후 자신의 좌표 공간 내에 Child를 위치시킨다.

(4. SwiftUI는 view의 모서리를 가장 가까운 픽셀로 반올림한다)

결국 부모와 자식의 상호작용만 집중하면 Layout이 결정된다고 한다! 

우리가 스유에서 자주쓰는 크기를 나타내는 모디파이어! 이것이 2번의 예이다. aspectRatio도 마찬가지인 경우.

자 숨겨진 4번의 과정! 원래라면 이렇게 안티앨리징이 존재한 상태로 보여져야하지만 SwiftUI가 알아서! 반올림해주기에 우리는 깔끔하게 볼 수 있는 이유이다!! 

자 갑자기 뚱딴지 같은 아보카도 토스트가 왜나왔냐? Text에다가 background modifier를 통해 우리는 실제 바운드를 알아볼때 용이하게 사용할 수있다고 알려준다. 

Swiftui에서 패딩값을 이렇게 아무것도 안써주면 뭐 주변에 있는 다른것들의 영향을 받아 알아서 환경에 맞게 Dynamic size로 선택을 한다고 한다. 

이제 이걸보면서 뷰의 Layout Process를 다시 공부해보자. 

1. 루트뷰가 야 너 어느정도 사용할수 있다를 알려준다. (여기서는 Safe area를 제외한 전부)

2. Background Modifier는 Layout Neutrual놈이라 Padding 으로 간다

3. Padding View는 Child의 Side에 10을 더할것을 알기에 Child한테 그만큼 적은 공간을 준다.

4. Text아보카도는 자신에게 필요한 width(Avocado Toast)를 가져와서 Padding View에게 반환한다. 

5. 패딩뷰는 각 Side에서 child보다 10씩 더 큰 크기를 Background에 준다.

6. Background 는 레이아웃 중립이여 그대로 사용한다. 

7. 그 위로 가기전 Color View에도 이 크기를 제공한다. 

8. 그 후 루트뷰에 주고 루트뷰는 가운데에 배치해준다


.

다른예시로 한번더 공부 ㄱㄱ.현재 이미지크기인 20, 20으로 고정된 뷰의 body size이다. 

절반정도 더 커지면 좋겠어 해서 30,30으로 frame Modifier적용해보았다. 

자 봐봐 이미지가 가지고 있는 사이즈는 커졌잖아. 근데 아보카도는 위와같이 여전히 20, 20 이다. 

Frame은 제약조건이 아니다. 액자라고 생각하면 되는 그냥 뷰이다!!

Frame은 30 30 을 주지만 이미지는 어 고마워 일단 받고 자신의 사이즈인 20,20을 사용하는 것이다. 즉 Child 자체가 자신의 크기를 선택한다는 것을 보여준다!


이렇게 Vstack이나 Hstack을 만들면 우리가 공간을 주지않아도 생기는 것을 볼 수 있다. 이는 HIG에 맞춰 Swiftui가 자동으로 해준다. 

만약 parent에게 충분한 크기를 받았다면 이렇게 자동으로 Spacer처리를 해준다.  그리고 전체의 크기를 3가지요소이기에 같은 크기만큼 배분해준다. 

하지만 이미지는 Fixed Size라고 앞에서 알려줬잖니? 그러면 어떠한 크기를 배분해주든 우리는 해당 이미지크기만큼 빼준다. 그러면 3자식중에 이미지끝났고 텍스트 두개남았지? 

빼주고 남은 영역을 반띵 해준다. 여기서 Text는 flexible size이기에 

 그러면 Delicious는 야 나 저정도 크기필요없는데? 난 이정도면 충분해~  그러면 그 Delicious가 차지하는 크기만큼 또 나머지 전체에서 빼준다. 그러면 나머지크기가 딱 Avacado Toast에게 맞는다. 

이로 인해 Text의 길이가 달라도 딱 Stack에 들어가는 구나! 만약 정확하게 공간을 3엔빵했다면 Avacado Toast는 ...이 나왔겠지요

그러면 이렇게 최종적으로 자식들의 크기가 다 정해지면 Stack은 정렬을 시작한다. 흠 정렬이 생각보다 나중에 되는 거였구나! 

 

그런데 만약 부모로부터 충분한 공간을 받지 못했어? 그러면 어떻게 쪼그라들어야 할까?

이렇게 우선순위가 높은것에 layoutPriority modifier를 붙이면 그것이 주로 나오고 나머지 dynamic한 크기를 가진놈이 줄어든다. 먼저 우선순위 제일 높은애를 배치해주고 나머지에서 사이즈를 정해주는것 같다 

Alignment

이렇게 alignment를 바텀으로 하면 해당 bounds의 밑으로 다 가는데 글씨의 크기, 이미지에따라 선이 뒤죽박죽인 모습을 볼 수 있다. 

🧑‍🎨아 미쳐버릴꺼같아요 ... 

그럴때 lastTextBaseline이라는 alignment를 하면 맨 밑을 기준으로 모두 맞춰줄수 있다. 와... 이런거 있는줄 몰랐다 맨날 leading trailiong 원툴인줄 알았던놈이 생각보다 더 대단했다. 

🧑‍🎨 이미지는 바텀라인으로부터 87.4프로만 위에 있고 나머지는 아래있으면 더 좋을꺼같아요... 부탁을 했다... 

그러면 이렇게 alignmentGuide를 이용하면 해결된다.

이 여러 스택이 섞여있는데 아 저 별들의 센터가 텍스트에 맞게 해주세요 🧑‍🎨

위와같이 alginment를 custom하면된다. 

 

추가로 Position & offset

둘이 자주 헷갈릴수 있다. 먼저 간략하게 차이점을 말하면 Offset은 layout Neutral 즉 그 밑의 컨텐츠에 똑같이 크기를 차지하여 위치를 옮기게 된다. 하지만 Position은 Parent뷰로부터 허락받은 공간을 전부 차지한다. 그래서 위치가 절대적으로 같은 위치에 위치하게 된다 .또한 position에 background를 주면 safearea무시