SwiftUI에서 UI 요소들을 정렬하고 배치하는 방법을 알아보는 것은 앱 개발의 가장 기본적인 단계다.
오늘은 SwiftUI에서 제공하는 세 가지 기본 스택 뷰 – VStack, HStack, ZStack의 사용법에 대해 알아보겠다.
스택이란?
스택(Stack)은 SwiftUI에서 여러 뷰를 그룹화하고 정렬하는 데 사용되는 컨테이너 뷰다. 각 스택은 방향에 따라 뷰를 정렬하는 방식이 다르다.

- VStack: 뷰를 수직(Vertical)으로 정렬
- HStack: 뷰를 수평(Horizontal)으로 정렬
- ZStack: 뷰를 깊이(Z축)로 쌓아 올림
VStack, HStack, ZStack 사용하는 방법
VStack 사용하기
VStack은 여러 뷰를 위에서 아래로 수직으로 배열한다. 텍스트, 이미지, 버튼 등 다양한 UI 요소를 포함할 수 있다.
기본 시그니처
VStack의 기본 구조는 다음과 같다:
swift// 기본 VStack
VStack {
// 내부 뷰들
}
// 속성을 가진 VStack
VStack(alignment: .leading, spacing: 10) {
// 내부 뷰들
}
alignment
: 수평 정렬 방식 (.leading, .center, .trailing)spacing
: 각 뷰 사이의 간격
예제 코드
swiftstruct VStackExample: View {
var body: some View {
VStack(alignment: .leading, spacing: 15) {
Text("제목")
.font(.title)
.fontWeight(.bold)
Text("부제목")
.font(.headline)
.foregroundColor(.gray)
Button("버튼 클릭") {
// 액션 코드
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.padding()
.background(Color.yellow.opacity(0.2))
.cornerRadius(12)
}
}
HStack 사용하기
HStack은 뷰를 왼쪽에서 오른쪽으로 수평으로 배열한다. 여러 항목을 나란히 표시할 때 유용하다.
기본 시그니처
swift// 기본 HStack
HStack {
// 내부 뷰들
}
// 속성을 가진 HStack
HStack(alignment: .top, spacing: 8) {
// 내부 뷰들
}
alignment
: 수직 정렬 방식 (.top, .center, .bottom, .firstTextBaseline, .lastTextBaseline)spacing
: 각 뷰 사이의 간격
예제 코드
swiftstruct HStackExample: View {
var body: some View {
HStack(alignment: .center, spacing: 12) {
Image(systemName: "star.fill")
.foregroundColor(.yellow)
Text("중요 항목")
.fontWeight(.semibold)
Spacer()
Text("상세 보기")
.foregroundColor(.blue)
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(8)
}
}
ZStack 사용하기
ZStack은 뷰를 앞뒤로(z축 방향으로) 중첩시킨다. 배경 위에 텍스트를 올리거나, 여러 레이어를 겹치게 할 때 사용한다.
기본 시그니처
swift// 기본 ZStack
ZStack {
// 내부 뷰들 (첫 번째 뷰가 맨 뒤, 마지막 뷰가 맨 앞)
}
// 속성을 가진 ZStack
ZStack(alignment: .topLeading) {
// 내부 뷰들
}
alignment
: 뷰의 정렬 방식 (.center, .topLeading, .top, .topTrailing 등)
예제 코드
swiftstruct ZStackExample: View {
var body: some View {
ZStack(alignment: .bottomTrailing) {
// 배경 이미지
Color.blue.opacity(0.3)
.frame(width: 300, height: 200)
.cornerRadius(15)
// 중간 레이어
VStack(alignment: .leading) {
Text("카드 제목")
.font(.title3)
.fontWeight(.bold)
Text("카드 설명")
.font(.body)
}
.padding()
.background(Color.white.opacity(0.8))
.cornerRadius(10)
.padding(20)
// 전면 레이어
Text("NEW")
.font(.caption)
.fontWeight(.bold)
.foregroundColor(.white)
.padding(8)
.background(Color.red)
.cornerRadius(8)
.padding(12)
}
}
}
스택 조합하기

실제 앱 개발에서는 이러한 스택들을 조합해서 복잡한 레이아웃을 구성한다. 스택 안에 다른 스택을 넣는 것도 가능하다.
swiftstruct CombinedStacksExample: View {
var body: some View {
VStack(spacing: 20) {
// 제목 영역
Text("스택 조합 예시")
.font(.title)
.fontWeight(.bold)
// 카드 목록
VStack(spacing: 12) {
// 첫 번째 카드
HStack {
Image(systemName: "swift")
.font(.largeTitle)
.foregroundColor(.orange)
VStack(alignment: .leading) {
Text("Swift")
.font(.headline)
Text("프로그래밍 언어")
.font(.subheadline)
.foregroundColor(.gray)
}
Spacer()
ZStack {
Circle()
.fill(Color.green)
.frame(width: 30, height: 30)
Text("A")
.foregroundColor(.white)
.fontWeight(.bold)
}
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(12)
// 두 번째 카드 (비슷한 구조)
HStack {
Image(systemName: "hammer.fill")
.font(.largeTitle)
.foregroundColor(.purple)
VStack(alignment: .leading) {
Text("SwiftUI")
.font(.headline)
Text("UI 프레임워크")
.font(.subheadline)
.foregroundColor(.gray)
}
Spacer()
ZStack {
Circle()
.fill(Color.blue)
.frame(width: 30, height: 30)
Text("B")
.foregroundColor(.white)
.fontWeight(.bold)
}
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(12)
}
.padding(.horizontal)
}
.padding()
}
}
스택의 성능 고려사항
많은 뷰를 포함하는 스택은 성능에 영향을 줄 수 있다. 특히 깊게 중첩된 스택은 성능 문제를 일으킬 수 있으므로 적절히 사용해야 한다.
- 불필요한 중첩을 피한다
- LazyVStack과 LazyHStack을 사용하여 필요할 때만 뷰를 로드한다.(스크롤 됐을 때 불러오는 뷰다.)
- Group을 사용하여 뷰를 그룹화하면서 불필요한 스택을 줄일 수 있다.
VStack, HStack, ZStack 사용법을 마치며
SwiftUI의 VStack, HStack, ZStack은 앱 UI를 구성하는 가장 기본적인 빌딩 블록이다. 이 세 가지 스택을 적절히 조합하면 거의 모든 UI 레이아웃을 만들 수 있다.
화면 크기에 따라 자동으로 조정되는 반응형 레이아웃을 구현하기 위해서는 이러한 스택들의 특성을 잘 이해하고 활용하는 것이 중요하다.
특히 iOS와 iPadOS, macOS에서 모두 잘 작동하는 앱을 만들고 싶다면 스택을 적절하게 사용하여 다양한 화면 크기에 대응할 수 있다.
더 자세한 정보는 Apple 공식 문서에서 확인할 수 있다.