[SwiftUI / Article] Building Layouts with Stack Views

beeeen:D·2023년 1월 9일
0

iOS

목록 보기
8/17
post-thumbnail
post-custom-banner

SwiftUI로 복잡한 레이아웃을 구성해보자 !

흔히 사용하는 HStack, VStack, ZStack은 단순 View이다.

HStack : 요소들을 수평으로 배치
VStack : 요소들을 수직으로 배치
ZStack : 요소들을 겹치게 배치

  • 처음에 별다른 설정없이 요소들을 배치하면, 요소들은 중앙에 정렬되고 각 요소들 사이에 약간의 spacing이 들어간다.
  • SpacerDivider와 같은 view modifier를 적재적소에 사용하면, 다양한 custom UI 작업이 가능하다.

1. 레이아웃 계층에 대해 생각해보자.

디자인된 화면을 코드로 옮기기 전에, 다양한 유형의 stack view를 어떻게 사용하여 레이아웃을 구성할지에 대해 먼저 고민해봐야 한다.
복잡하게 구성된 화면을 잘게 쪼개어 볼 줄 알아야 한다.

  • ZStack에는 프로필 사진을 나타내는 Image view와 그 위에 반투명 HStack이 있다.
  • HStack에는 수직으로 나열된 두 개의 텍스트 포함하기 위해 VStack이 있고 VStack을 왼쪽으로 밀어내기 위해 Spacer도 포함하고 있다.
struct ProfileView: View {
	var body: some View {
    	ZStack(alignment: .bottom) {
        	Image("ProfilePicture")
            	.resizable
                .aspectRatio(contentMode: .fit)
            HStack {
            	VStack(alignment: .leading) {
                	Text("Rachel Chiseck")
                    	.font(.headline)
                    Text("Chief Executive Officer")
                    	.font(.subheadline)
                }
                Spacer()
            }
            .padding()
            .foregroundColor(.primary)
            .background(Color.primary
            				.colorInvert()
                            .opacity(0.75))    
		}
    }
}

2. Alignment와 Spacer를 사용해서 View를 배치해보자.

Stack 내에 포함된 view들을 정렬하려면,

  • alignment 프로퍼티
  • Spacer
  • Divider

를 조합하여 사용하면 된다.

VStack의 alignment 프로퍼티

  • HorizontalAlignment🔗를 사용하는 수평 정렬에만 적용 🆗

HStack의 alignment 프로퍼티

  • VerticalAlignment🔗를 사용하는 수직 정렬에만 적용 🆗

Alignment 🔗

  • 두 축을 따라 ZStack 내부의 view 정렬 가능 🆗

Spacer 🔗

  • HStack 또는 VStack의 주된 축을 따라 view 정렬
  • 컨텐츠를 한 쪽으로 밀기 위해, Spacer를 사용하여 나머지 가용 공간을 채워버림

Divider 🔗

  • Divider 또한 Stack의 하위 view 사이에 공간을 추가하지만, Stack의 축을 가로질러 선을 그릴 수 있는 충분한 공간만 삽입한다.
  • 가용 공간을 채우기 위해 확장하는 Spacer와는 다름

Spacer와 Divider 비교

  • VStack

  • VStack + Spacer()

  • VStack + Divider()

  • HStack + Divider()

3. 명시적 레이아웃 대신 적응형 레이아웃을 만들자.

명시적인 Height와 Width로 View 프레임 지정 ❌
구조 및 계층을 정의하고 가용 공간을 채울 수 있도록 View 확장 ✅

  • 다양한 크기의 디바이스 및 플랫폼에 쉽게 적용 가능

명시적인 레이아웃 조정 방법에는

  • frame(width:height:alignment:) 🔗
  • position(x:y:) 🔗

와 같은 방법이 있지만, adaptive & flexible하게 레이아웃을 구성할 수 없을 때만 사용하자.

❗️ view layout 미세 조정하는 방법은 Making Fine Adjustments to a View's Position 참고.

4. 다른 방식으로 Depth 추가하기.

Depth 추가하는 방법은 앞에서 ZStack을 사용하면 된다고 했는데, 이 외에도 경우에 따라 다른 방법을 사용할 수 있다.

Modifier 1. overlay

  • overlay(_:alignment:) 🔗 Deprecated
    overlay(alignment:content:) 🔗

view 위에 view를 배치하는 modifier

Modifier 2. background

  • background(_:alignment:) 🔗 Deprecated
    background(alignment:content:) 🔗

수정 중인 view 뒤에 다른 view를 배치하는 modifier

ZStack, overlay, background 비교

  • ZStack

  • Overlay

  • background

최종 레이아웃의 크기를 어떻게 결정할 것인지에 따라서,

  • stack-based(ZStack 사용)
    모든 요소가 포함된 view의 최종 사이즈를 가져올 때 사용

  • view modifier(overlay, background 사용)
    레이아웃 크기를 담당하는 지배적인 view가 있을 경우 사용

두 접근 방식 중 하나를 선택하여 사용하면 된다.

Overlay 예시 코드

struct ProfileViewWithOverlay: View {
    var body: some View {
        VStack {
            Image("ProfilePicture")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .overlay(ProfileDetail(), alignment: .bottom)
        }
    }
}

struct ProfileDetail: View {
    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text("Rachael Chiseck")
                    .font(.headline)
                Text("Chief Executive Officer")
                    .font(.subheadline)
            }
            Spacer()
        }
        .padding()
        .foregroundColor(.primary)
        .background(Color.primary
                        .colorInvert()
                        .opacity(0.75))
    }
}

Tip!

요소 사이에는 기본적으로 들어가는 spacing이 있다.
HStack은 수평으로, VStack은 수직으로

HStack {
	Text("First")
    Text("Second")
}
VStack {
	Text("First")
    Text("Second")
}

spacing 계산을 쉽게 하려면, 아래처럼 (spacing: 0)으로 한 다음, .padding()을 넣어주면 된다.

VStack(spacing: 0) {
	Text("First")
    	.padding(.bottom, 16)
    Text("Second")
}

원문
Building layouts with stack views 🔗

profile
iOS developer 👩🏻‍💻
post-custom-banner

0개의 댓글