SwiftUI에서 Atomic Design을 적용할 때 실제 컴포넌트 구조를 어떻게 나눌지와 코드 스타일에 중점을 두고 설명하겠습니다.
Atomic Design을 SwiftUI에 적용할 때는 아래의 기준을 고려했습니다.
Atoms는 SwiftUI에서 가장 작은 UI 구성 요소로 단일 역할을 수행하고 독립적으로 사용할 수 있는 컴포넌트입니다. 예를 들어 색상이나 크기 스타일이 적용된 Text, Button 등을 독립된 컴포넌트로 정의합니다. Atoms는 앱 전체에서 재사용될 가능성이 높기 때문에 일관된 스타일과 기능을 적용하기 좋습니다.
import SwiftUI
// 버튼 Atom
struct PrimaryButton: View {
let title: String
let action: () -> Void
var body: some View {
Button(action: action) {
Text(title)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
}
}
// 아이콘 Atom
struct Icon: View {
let systemName: String
var size: CGFloat = 24
var body: some View {
Image(systemName: systemName)
.resizable()
.frame(width: size, height: size)
}
}
Molecules는 Atoms를 조합하여 간단한 기능을 구현하는 컴포넌트입니다. SwiftUI에서 Molecules는 하나의 목적을 가진 UI 요소로 UI의 일부 기능을 수행하는 작은 컴포넌트로 만듭니다. 여기서는 Atoms를 조합하여 특정한 형태의 뷰를 구성합니다.
// 텍스트와 아이콘을 조합한 Molecule
struct LabelWithIcon: View {
let text: String
let iconName: String
var body: some View {
HStack {
Icon(systemName: iconName)
Text(text)
.font(.headline)
}
}
}
// 입력 필드 Molecule
struct InputField: View {
@Binding var text: String
let placeholder: String
var body: some View {
TextField(placeholder, text: $text)
.padding()
.background(Color.gray.opacity(0.2))
.cornerRadius(8)
}
}
Organisms는 여러 Molecules와 Atoms를 결합하여 특정 기능을 완성하는 컴포넌트입니다. SwiftUI에서는 Organisms가 실질적으로 UI 기능을 담당하므로, 독립적인 로직을 가지고 상호작용을 수행하는 컴포넌트가 됩니다. Organisms는 보통 하나의 기능 단위를 수행하며 자주 사용되는 기능들을 그룹화합니다.
// 검색창 Organism
struct SearchBar: View {
@State private var searchText = ""
var body: some View {
VStack {
InputField(text: $searchText, placeholder: "Search")
PrimaryButton(title: "Search") {
print("Search action with: \(searchText)")
}
}
.padding()
}
}
// 프로필 카드 Organism
struct ProfileCard: View {
let name: String
let jobTitle: String
var body: some View {
VStack {
Icon(systemName: "person.circle.fill")
.frame(width: 64, height: 64)
.padding(.bottom, 8)
Text(name)
.font(.title2)
Text(jobTitle)
.font(.subheadline)
.foregroundColor(.gray)
}
.padding()
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 5)
}
}
Templates는 Atoms, Molecules, Organisms를 조합하여 화면의 전체 레이아웃을 구성합니다. SwiftUI에서는 Templates를 통해 기능을 구현하지 않고 배치와 레이아웃만을 설정합니다. 예를 들어 로그인 화면, 사용자 프로필 화면 등의 레이아웃을 잡을 때 사용합니다.
// 프로필 화면 레이아웃 템플릿
struct ProfileTemplate: View {
let name: String
let jobTitle: String
var body: some View {
VStack(spacing: 20) {
ProfileCard(name: name, jobTitle: jobTitle)
SearchBar()
}
.padding()
.background(Color.gray.opacity(0.1))
}
}
Pages는 Templates에 실제 데이터를 주입하여 최종 화면을 구성하는 단계입니다. SwiftUI에서는 최종 사용자가 보게 될 화면을 Pages에서 구현하며, ViewModel을 주입하거나 데이터 로딩 로직을 구현합니다. 이 단계에서 API 호출이나 로컬 데이터베이스에서 데이터를 가져와서 화면에 반영할 수 있습니다.
// ViewModel 정의
class ProfileViewModel: ObservableObject {
@Published var name: String = "John Doe"
@Published var jobTitle: String = "iOS Developer"
func loadProfile() {
// 프로필 데이터 로드 로직
}
}
// 최종 프로필 페이지
struct ProfilePage: View {
@StateObject private var viewModel = ProfileViewModel()
var body: some View {
ProfileTemplate(name: viewModel.name, jobTitle: viewModel.jobTitle)
.onAppear {
viewModel.loadProfile()
}
}
}
이렇게 Atomic Design을 SwiftUI에 적용하면 구조가 명확하고 재사용 가능한 컴포넌트로 앱을 구성할 수 있습니다. Atoms부터 Pages까지 각 단계를 명확히 구분하여 앱의 확장성과 유지보수성을 높일 수 있습니다.