재사용 가능한 SwiftUI 컴포넌트 라이브러리 구축
Source: Dev.to
SwiftUI는 UI를 쉽게 만들 수 있게 해 주지만, 전체 앱에서 일관된 모습을 유지하는 재사용 가능한 컴포넌트를 만드는 것은 또 다른 도전 과제입니다.
앱이 성장함에 따라 UI 중복이 실제 문제로 떠오릅니다:
- 반복되는 버튼 스타일
- 일관되지 않은 카드 형태
- 중복된 텍스트 모디파이어
- 복사‑붙여넣기 그림자
- 동일 레이아웃의 여러 버전
컴포넌트 라이브러리가 이 모든 문제를 해결합니다.
오늘은 다음을 포함하는 현대적이고 확장 가능한 Apple‑스타일 SwiftUI 컴포넌트 라이브러리를 만드는 방법을 배웁니다:
- 버튼
- 카드
- 텍스트 필드
- 플로팅 패널
- 칩
- 디자인 토큰(색상, 라디우스, 그림자)
- 재사용 가능한 모디파이어
- 일관된 스타일링
이것은 제가 실제 프로덕션 앱에서 사용하는 정확한 구조입니다. 함께 만들어 봅시다. 🚀
1. Design 폴더부터 시작하기
Design/
├── Colors.swift
├── Radii.swift
├── Shadows.swift
└── Typography.swift
Colors.swift
enum AppColor {
static let primary = Color.blue
static let background = Color(.systemBackground)
static let glassStroke = Color.white.opacity(0.25)
}
Radii.swift
enum AppRadius {
static let small: CGFloat = 10
static let medium: CGFloat = 16
static let large: CGFloat = 22
}
Shadows.swift
enum AppShadow {
static let card = Color.black.opacity(0.18)
static let glow = Color.blue.opacity(0.3)
}
Typography.swift
enum AppFont {
static let title = Font.system(.title3, design: .rounded).bold()
static let body = Font.system(.body, design: .rounded)
}
한 곳에서 관리 → 전체 앱 일관성 확보.
2. 재사용 가능한 버튼 스타일
PrimaryButton
struct PrimaryButton: View {
let title: String
let action: () -> Void
var body: some View {
Button(action: action) {
Text(title)
.font(AppFont.body.bold())
.padding(.horizontal, 28)
.padding(.vertical, 14)
.background(AppColor.primary)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: AppRadius.medium, style: .continuous))
.shadow(color: AppShadow.card, radius: 16, y: 8)
}
}
}
사용 예시
PrimaryButton(title: "Continue") {
print("Pressed")
}
3. Glass Card 컴포넌트 (재사용 가능)
struct GlassCard: View {
@ViewBuilder let content: () -> Content
var body: some View {
content()
.padding(20)
.background(.ultraThinMaterial)
.clipShape(RoundedRectangle(cornerRadius: AppRadius.large, style: .continuous))
.overlay(
RoundedRectangle(cornerRadius: AppRadius.large, style: .continuous)
.stroke(AppColor.glassStroke, lineWidth: 1)
)
.shadow(color: AppShadow.card, radius: 24, y: 12)
}
}
사용 예시
GlassCard {
VStack(alignment: .leading) {
Text("Glass Card")
.font(AppFont.title)
Text("Reusable glassmorphic component.")
.foregroundColor(.secondary)
}
}
4. TextField 컴포넌트 (모던하고 깔끔)
struct AppTextField: View {
var title: String
@Binding var text: String
var body: some View {
TextField(title, text: $text)
.padding(.horizontal, 14)
.padding(.vertical, 12)
.background(.ultraThinMaterial)
.clipShape(RoundedRectangle(cornerRadius: AppRadius.medium))
.overlay(
RoundedRectangle(cornerRadius: AppRadius.medium)
.stroke(AppColor.glassStroke)
)
.shadow(color: AppShadow.card.opacity(0.25), radius: 12, y: 6)
}
}
사용 예시
@State private var name = ""
AppTextField(title: "Name", text: $name)
5. Chips / Tags
struct Chip: View {
let label: String
let icon: String?
var body: some View {
HStack(spacing: 6) {
if let icon { Image(systemName: icon) }
Text(label)
}
.font(.caption)
.padding(.horizontal, 12)
.padding(.vertical, 8)
.background(.ultraThinMaterial)
.clipShape(Capsule())
.overlay(Capsule().stroke(AppColor.glassStroke))
}
}
예시
HStack {
Chip(label: "SwiftUI", icon: "swift")
Chip(label: "Design", icon: "paintbrush")
}
6. Floating Panel (재사용 가능한 Bottom Sheet 상단 섹션)
struct FloatingPanel: View {
@ViewBuilder let content: () -> Content
var body: some View {
VStack(spacing: 0) {
Capsule()
.fill(AppColor.glassStroke)
.frame(width: 40, height: 6)
.padding(.top, 10)
content()
.padding()
}
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: AppRadius.large, style: .continuous))
.shadow(color: .black.opacity(0.25), radius: 30, y: 14)
}
}
7. 재사용 가능한 모디파이어 (강력한 도구!)
struct CardPadding: ViewModifier {
func body(content: Content) -> some View {
content
.padding(20)
.clipShape(RoundedRectangle(cornerRadius: AppRadius.large))
}
}
extension View {
func cardPadding() -> some View {
modifier(CardPadding())
}
}
모디파이어는 뷰를 깔끔하고 선언적으로 유지해 줍니다.
8. 권장 폴더 구조
Design/
│ Colors.swift
│ Radii.swift
│ Shadows.swift
│ Typography.swift
│
Components/
│ Buttons/
│ Cards/
│ TextFields/
│ Panels/
│ Chips/
│ Modifiers/
모든 것이 깔끔하고, 모든 것이 확장 가능합니다.
마무리 생각
SwiftUI 컴포넌트 라이브러리를 사용하면 다음을 얻을 수 있습니다:
- 일관된 디자인
- 빠른 반복 작업
- 재사용 가능한 빌딩 블록
- 확장 가능한 아키텍처
- 팀 온보딩 용이
- 더 다듬어진 UI
이것이 “스크린을 만들기”에서 “시스템을 만들기”로 전환하는 방법입니다.