
Apple Developer Academy @ POSTECH 입과 후 첫 번째 SwiftUI 학습 기록입니다.
제가 스스로 연습과 학습을 위한 학습입니다. 애플아카데미에서 제공하는 학습자료가 아닌 점 알려드립니다. 전혀 무관함을 알려드립니다. 개인프로젝트입니다.
SwiftUI를 처음 접하면서 가장 먼저 만들어본 것은 F1 레이싱 앱의 헤더 컴포넌트입니다. 단순해 보이지만 레이아웃의 핵심 개념인 HStack, VStack, ZStack, Spacer를 모두 활용할 수 있는 좋은 출발점이었습니다.
완성된 헤더는 아래와 같습니다.
☰ MONACO GRAND PRIX ⚙
🔴 Live • Lap 42/78
파일을 역할별로 분리하는 것부터 시작했습니다.
practiceApp/
├── Assets.xcassets
├── Components/
│ └── Header.swift # 재사용 가능한 UI 부품
├── practiceApp.swift # @main 앱 진입점
└── Screens/
└── HomeView.swift # 실제 화면
Components/ — 여러 화면에서 재사용할 수 있는 작은 UI 단위Screens/ — 하나의 완성된 화면 단위
ContentView.swift는 필수가 아닙니다.@main파일에서 원하는 View를 바로 진입점으로 지정할 수 있습니다.
@main
struct practiceApp: App {
var body: some Scene {
WindowGroup {
HomeView() // ContentView 없이 바로 연결
}
}
}
SwiftUI의 레이아웃은 세 가지 Stack으로 구성됩니다.
| Stack | 방향 | 주요 용도 |
|---|---|---|
HStack | 가로 (←→) | 아이콘, 버튼 나열 |
VStack | 세로 (↑↓) | 제목 + 부제목 배치 |
ZStack | 앞뒤 겹치기 | 배경 위에 컨텐츠 올리기 |
각 Stack은 alignment 파라미터로 정렬 방향을 지정할 수 있습니다.
VStack(alignment: .leading) { } // 왼쪽 정렬
ZStack(alignment: .top) { } // 위쪽 정렬
Spacer()는 남은 공간을 전부 차지하는 투명한 뷰입니다. 직접 무언가를 밀어내는 것이 아니라, 공간을 먼저 차지함으로써 다른 뷰들이 상대적으로 밀려나는 효과를 만듭니다.
// HStack — 양쪽 끝으로 분리
HStack {
Text("왼쪽")
Spacer()
Text("오른쪽")
}
// VStack — 헤더를 상단에 고정
VStack {
Header()
Spacer()
}
ZStack으로 Color.black을 배경으로 먼저 깔고, 그 위에 컨텐츠를 올립니다. .ignoresSafeArea()를 적용하면 노치/홈바 영역까지 색상이 채워집니다.
struct HomeView: View {
var body: some View {
ZStack(alignment: .top) {
Color.black
.ignoresSafeArea() // Safe Area 영역까지 검은색
VStack(alignment: .leading) {
Header()
Spacer()
}
}
}
}
Apple이 제공하는 6,000개 이상의 무료 아이콘 라이브러리입니다. 별도 설치 없이 Image(systemName:)으로 바로 사용할 수 있습니다.
Image(systemName: "line.3.horizontal") // 햄버거 메뉴
Image(systemName: "gearshape") // 설정
Image(systemName: "magnifyingglass") // 검색
Mac App Store에서 SF Symbols 앱을 설치하면 아이콘을 카테고리별로 검색하고 이름을 바로 복사할 수 있어 개발 속도가 훨씬 빨라집니다.
extension으로 Color를 확장하면 프로젝트 전반에서 .f1Red처럼 기본 색상처럼 사용할 수 있습니다.
extension Color {
static let f1Red = Color(red: 225/255, green: 6/255, blue: 0/255)
}
// 사용
.foregroundColor(.f1Red)
.foregroundColor(.f1Red.opacity(0.3)) // 투명도 조절
ZStack으로 도형과 버튼을 겹쳐서 배경이 있는 버튼을 만들 수 있습니다.
ZStack {
RoundedRectangle(cornerRadius: 10)
.frame(width: 50, height: 50)
.foregroundColor(.f1Red.opacity(0.3))
Button(action: {}) {
Image(systemName: "gearshape")
.foregroundColor(.red)
.font(.system(size: 30))
}
}
// Header.swift
import SwiftUI
extension Color {
static let f1Red = Color(red: 225/255, green: 6/255, blue: 0/255)
}
struct Header: View {
var body: some View {
HStack {
Button(action: {}) {
Image(systemName: "line.3.horizontal")
.foregroundColor(.red)
.font(.system(size: 30))
}
VStack(alignment: .leading) {
Text("Monaco Grand Prix")
.font(.title3)
.bold()
.foregroundColor(.white)
HStack {
Circle()
.frame(width: 8, height: 8)
.foregroundColor(.red)
Text("Live • Lap 42/78")
.font(.title3)
.bold()
.foregroundColor(.red)
}
}
.padding()
Spacer()
ZStack {
RoundedRectangle(cornerRadius: 10)
.frame(width: 50, height: 50)
.foregroundColor(.f1Red.opacity(0.3))
Button(action: {}) {
Image(systemName: "gearshape")
.foregroundColor(.red)
.font(.system(size: 30))
}
}
}
.padding(.horizontal)
}
}
첫 SwiftUI 컴포넌트를 만들면서 느낀 것은, UIKit과 달리 레이아웃을 선언적으로 구성한다는 점이 매우 직관적이라는 것입니다. Stack을 조합하고 Spacer로 공간을 배분하는 방식에 익숙해지면 복잡한 레이아웃도 명확하게 구조화할 수 있을 것 같습니다.
다음에는 @State와 @Binding을 활용해 버튼에 실제 동작을 연결하고, 바텀 네비게이션바를 통한 화면 전환을 구현할 예정입니다.
학습 기록은 GitHub AppleDeveloperAcademy_TIL에서 확인할 수 있습니다.