ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [WWDC19] Building Custom Views with SwiftUI Session, SwiftUI Layout 크기 메커니즘 알아보기
    IOS/WWDC24 2024. 9. 21. 09:04

    [Introduce]

    이번 글은 WWDC19 Building Custom View with SwiftUI 영상에 소개된 SwiftUI View 메커니즘에 소개하려 합니다.

    SwiftUI를 활용한 iOS, iPadOS 등 컴포넌트 사용법을 습득하기에 급급했었습니다. Apple 생태계 개발에 입문하시는 분들에게 이번 영상을 계기로 좀 더 SwiftUI의 메커니즘을 이해하는 데 도움이 되는 마음으로 글을 작성하게 되었습니다.

     

    struct ContentView: View {
    	var body: some View {
    		Text("Hello World")
    	}
    }
    

    간단한 코드이지만, 실제 어떤 계층 구조를 가지고 있는지 생각해 보신 적 있으신가요?

    SwiftUI에선 위 코드를 어떤 구조로 가지고 있을까요?

    SwiftUI도 UIkit처럼 Root View를 토대로 하위 뷰들이 계층적 구조를 띄고 있습니다. Text가 있기 전 그 위에 ContentView가 있고, 그 상위뷰인 iOS화면에 안전영역을 뺀 기기 화면 크기를 가지는 RootView가 있습니다.

    body 프로퍼티를 가지는 View들은(ContentView 같이) layout neutral(레이아웃 중립)이라 불리고 body에 의해서 bounds가 정의됩니다. 이 layout neutral은 body와 같은 뷰로 취급할 수 있습니다.

    더보기

    layout neutral 

    layout neutral 개념은 SwiftUI 계층 구조 단순화 및 레이아웃 최적화 계산 메커니즘에 사용되는 개념입니다.

    body를 정의할 때 최상위 레이아웃 크기나 위치를 별도로 고려할 필요도 없이 body구현에만 신경 쓰면 됩니다.

    위 그림을 다음과 같이 contentView내 body가 Text 하나만 가지고 있으니 다음과 같이 표현합니다.

     

    [Layout Procedure]

     

    1. Parent Proposes a size for child

    parent view size

    • view 계층 구조 오른쪽에 root View에 큰 화살표로 safe area 전체크기를 나타내고 있습니다.
    • SwiftUI에선 이 크기를 바탕으로 자식 뷰인(Text)에 사이즈를 제안합니다. 그렇다면 자식 뷰인 Text는 부모의 크기를 알게 되고 자기 자신은 어느 정도의 크기인지 응답하게 됩니다.(SwiftUI에선 부모 뷰가 자식의 뷰 크기를 강제로 지정할 수 없습니다. 
    • 이후 Root View는 Text를 가운데에 위치시킵니다.

     

    2. child chooses its own size

     

    뷰는 자기 자신의 크기를 지정할 수 있습니다. 다음과 같은 코드를 보면

    • Image 프레임이 50 * 10으로 지정되어 있습니다. 이는 고정된 값으로 뷰는 항상 이 크기 프레임 크기를 보장합니다.

    • background modifer를 추가했을 땐 다음과 background Text를 감싸고 Color를 또 다른 자식으로 두는 계층 구조를 가집니다.
    • padding의 경우 특정 값을 파라미터로 전달하지 않으면 swiftUI에선 플랫폼 환경에 따라 자동으로 패딩 크기를 설정합니다

    위 그림은 top, bottom, leading, trailing 방향으로 패딩이 적용된 그림입니다.

     

    ✅여기서 잠깐! padding에 10 point의 사이즈를 지정하면 다음과 같이 있다면 SwiftUI는 어떻게 처리하게 될까요?

     

    1. RootView에서 화면 전체 사이즈를 background view에 제안합니다.

    ❗️backgroundview layout netural이기 때문에 곧바로 자식 계층인 paddingView에게 사이즈를 제안합니다.

     

    2. Text상위에 존재하는 Padding view는 각 면에 10 point만큼 적은 크기를 자식인 텍스트에게 제안합니다.

    3. 텍스트는 필요한 너비를 설정하고 상위 뷰인 padding view에게 반환합니다.

    4. 패딩뷰는 각 면에 10포인트씩 자신의 자식보다 더 커야 한다는 걸 알게 됩니다. 이후 패딩뷰는 자신의 좌표 공간에 텍스트를 적절히 배치하게 됩니다.

    5. background가 layour netural이므로 이제 Root View에 그 크기를 전달하기 전 또 다른 자식 계층인 Color 계층에게 padding이 적용된 크기를 제안하고 Color는 이 크기를 적용합니다.

    6. 이렇게 다 적용되면 background는 Root View에 사이즈를 보고하고, Root View는 이를 가운데에 적절히 배치하게 됩니다.

     

    [Stack의 Layout Procedure]

    🔥Stack의 경우 레이아웃은 어떻게 결정될까요?

     

    lineLimit을 1로 강제로 준 HStack입니다. 오른쪽 그림은 HStack 내부 요소가 크기 줄어든다면 텍스트가 잘리게 됩니다. 이런 레이아웃을 가지게 된 이유를 플로우로 설명드리겠습니다.

     

    [parent view space가 충분할 때]

    1. Hstack은 내부 간격의 크기(S0, S1)를 제안된 너비(Parent View)에서 제외합니다. 

     

    2. 다음은 Hstack은 자식 뷰의 크기만 제안할 뿐 사이즈를 정확히 모릅니다. 따라서 3개의 자식이 있으므로 균일하게 3등분을 시도합니다.

    이후 세 개 중 가장 flexible이 낮은 child View에 적합한 크기를 제안하게 됩니다. 여기선 아보카도 이미지가 가장 유연성이 낮습니다. (이미지가 Text보다 유연성이 낮다 판단합니다.)

    더보기

    🔥유연성의 낮고 높은 판단 기준

    유연성의 낮고 높은 판단 기준은 크기가 고정돼있거나 추가 공간을 차지하려고 하지 않는 뷰를 말합니다 Text, 이미지, frame(width:height:) fixedSize()가 있고 Spacer(), frame에서 minWidht, minHeight, maxHeight 같은 건 유연성이 높다고 판단합니다.

    3. 아보카드 콘텐츠 크기만큼 Hstack이 알고 있는 크기를 제외시키고 할당되지 않은 자식은 2개 남았으니 균일하게 2등분을 시도합니다.

    2번과 동일하게 가장 felxible이 낮은 자식뷰에게 크기를 제안하게 됩니다. (여기선 Text길이가 작은 게 유연성이 낮다 판단합니다.)

     

    4. 마지막으로 Hsatck은 남아있는 Declicious 고유 길이를 뺀 나머지 크기를 마지막 아보카드 텍스트에게 제안합니다.

     

    [parent view space가 충분하지 않을 때]

    만약 display크기보다 Vstack 내 요소들 길이가 작을 경우엔 어떨까요?

     

    위 그림을 보면, 글자 고유 길이 + 이미지 길이 보다 Hstack이 가지는 길이가 작은 그림입니다. 이럴 경우 글자가 잘리게 됩니다. 이럴경우 Avocado Toast 우선순위를 0 → 1로 상승시킨 레이아웃은 점 세 개의 길이 (Delicious의 최소길이)와 이미지 크기를 뺀 나머지 표현 가능 범위 내에 아보카드 토스트 길이가 결정되는 메커니즘을 가지고 있습니다.

     

     

    [결론]

    SwiftUI 뷰 구조

    • SwiftUI는 Root View를 기반으로 하위 뷰들이 계층적 구조를 가집니다⁠
    • body 프로퍼티를 가진 View들은 layout neutral이며, body와 같은 뷰로 취급됩니다⁠.

    레이아웃 절차

    • 부모 뷰가 자식 뷰에게 크기를 제안하고, 자식 뷰는 자신의 크기를 선택합니다⁠⁠
    • 뷰는 자신의 크기를 지정할 수 있으며, 수정자(modifier)를 통해 크기와 레이아웃을 조절할 수 있습니다⁠⁠.

    Stack 레이아웃

    • HStack은 내부 요소의 크기와 간격을 고려하여 균일하게 공간을 분배합니다⁠⁠
    • 유연성이 낮은 뷰부터 크기를 할당하고, 남은 공간을 다른 뷰에 분배합니다⁠
    • 공간이 부족할 경우, 우선순위를 조절하여 뷰의 크기를 결정할 수 있습니다⁠⁠

    [Reference]

    https://developer.apple.com/wwdc19/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

     

    'IOS > WWDC24' 카테고리의 다른 글

    [WWDC24] Translation API_한번에 여러 컴포넌트 번역하기  (0) 2024.09.14
    [WWDC24] Translation API_소개  (3) 2024.09.08
Designed by Tistory.