SwiftUI의 Section은 Form 또는 List 내에서 요소를 논리적으로 그룹화하기 위한 컨테이너 컴포넌트입니다. 시스템 간격, 둥근 모서리, 선택적 헤더 및 푸터가 있는 시각적 블록으로 콘텐츠를 표시합니다. Apple Developer Documentation (2025)에 따르면 Section은 데이터를 관리하지 않으며 프레젠테이션만 구성합니다. 모든 자식 요소는 스타일과 간격을 상속받아 폼과 리스트의 구조화된 표시를 제공합니다.
핵심 요점
Section은 Form 및 List 컨테이너 내에서 요소를 그룹화하도록 설계된 SwiftUI의 구조적 컴포넌트입니다. VStack이나 HStack과 달리 Section은 시스템 간격, 헤더와 푸터, 그리고 iOS에서 둥근 모서리 블록 형태의 시각적 그룹 강조를 추가합니다.
Section은 자식 요소의 동작을 변경하지 않으며 프레젠테이션만 구성합니다. Section 내의 모든 컨트롤(Picker, Toggle, TextField)은 평소처럼 작동하지만 시각적으로 논리적 그룹으로 결합됩니다. 이는 사용자가 데이터 입력 구조에서 빠르게 방향을 잡아야 하는 화면 폼에서 특히 중요합니다.
시스템은 섹션 간 간격을 자동으로 관리합니다. iOS에서 Section 간 거리는 16-20포인트, Section 내 요소 간 거리는 0(행 구분선)입니다. 개발자는 패딩 수정자를 통해 이러한 간격을 변경할 수 없습니다. 일관된 외관을 보장하기 위해 시스템에 의해 제어됩니다.
Section은 두 가지 선택적 매개변수를 허용합니다. header는 그룹의 제목, footer는 그룹 아래의 설명 텍스트입니다. 헤더는 섹션 요소 위에 굵은 캡션 스타일 폰트로 표시되고, 푸터는 회색의 더 작은 폰트로 표시됩니다. 두 매개변수 모두 Text뿐만 아니라 모든 SwiftUI View를 허용합니다.
Section의 헤더는 사용자가 그룹 내 요소가 어떤 카테고리에 속하는지 이해하는 데 도움을 줍니다. 예를 들어 설정 화면에서 “알림”, “개인정보”, “계정”과 같은 헤더는 사용자를 즉시 안내합니다. 푸터는 설명에 유용합니다. “회의 중에는 알림을 끄세요” 또는 “비밀번호는 8자 이상이어야 합니다.” 푸터는 필요할 때 자동으로 여러 줄로 줄바꿈됩니다.
Section(
header: Text("Account Security"),
footer: Text("Use a strong password with at least 8 characters.")
) {
SecureField("Current password", text: $currentPassword)
SecureField("New password", text: $newPassword)
}
예제에서 Section은 “Account Security” 헤더와 비밀번호 보안 조언이 포함된 푸터가 있습니다. 사용자는 헤더를 섹션 레이블로 보고 두 필드를 입력한 후 즉시 아래 경고를 읽습니다. 이 구조는 섹션에 대한 모든 정보가 별도의 도움말 페이지로 이동할 필요 없이 하나의 화면에 있기 때문에 UX를 향상시킵니다.
Section은 Form과 List 모두에서 작동하지만 시각적 표현이 다릅니다. Form에서 Section은 둥근 모서리와 시스템 배경이 있는 블록으로 표시되며 간격으로 인접한 섹션과 분리됩니다. List에서 Section은 plain 스타일(배경과 둥근 모서리 없음) 또는 inset-grouped(Form과 유사한 둥근 블록)를 사용할 수 있습니다.
컨테이너 선택은 Section의 스타일에 영향을 미칩니다. 동일한 콘텐츠의 Section을 Form과 List(.insetGrouped 스타일)에 배치하면 결과가 동일합니다. 그러나 Form은 기본적으로 시스템 간격을 추가하고 grouped 스타일을 사용하는 반면, List는 .listStyle(.insetGrouped) 수정자를 통해 명시적인 스타일 지정이 필요합니다.
| 컨테이너 | 기본 Section | 사용 가능한 스타일 |
|---|---|---|
| Form | 둥근 모서리의 InsetGrouped | .grouped (Form만 해당) |
| List | Plain — 섹션 배경 없음 | .plain, .inset, .insetGrouped, .sidebar |
List에서 동일한 모양을 얻으려면 .listStyle(.insetGrouped)를 사용하세요. 이 스타일은 Form의 모양을 모방하며 List로 구축된 설정 화면에 적합합니다. 표준 데이터 목록의 경우 섹션 강조 표시 없이 행 사이에 얇은 구분선이 있는 .plain을 사용하세요.
Section은 ForEach를 통해 동적 개수의 요소를 포함할 수 있습니다. 이를 통해 전체 그룹의 헤더와 푸터를 유지하면서 반복 요소가 있는 그룹을 만들 수 있습니다. Section 내의 ForEach는 데이터 컬렉션을 반복하고 섹션 구조를 깨뜨리지 않고 각 요소에 대한 자식 View를 생성합니다.
동적 섹션은 옵션 수가 가변적인 설정 화면에 유용합니다. 사용 가능한 언어 목록, 연결된 장치 또는 푸시 구독. 섹션 헤더는 정적으로 유지되고 콘텐츠는 데이터에 따라 변경됩니다.
struct DynamicSectionView: View {
let categories = ["Work", "Personal", "Finance", "Health"]
@State private var selected = Set<String>()
var body: some View {
Form {
Section(header: Text("Categories"),
footer: Text("Select your preferred categories")) {
ForEach(categories, id: \.self) { category in
Toggle(category, isOn: Binding(
get: { selected.contains(category) },
set: { if $0 { selected.insert(category) }
else { selected.remove(category) } }
))
}
}
Section {
Text("Selected: \(selected.count) categories")
.foregroundStyle(.secondary)
}
}
}
}
이 예제에서 ForEach는 categories 배열의 각 카테고리에 대한 Toggle을 생성합니다. 섹션의 헤더와 푸터는 한 번 설정되고 전체 그룹에 적용됩니다. 두 번째 섹션은 선택된 카테고리 수를 표시합니다. 이는 ForEach에 의존하지 않고 정적으로 유지됩니다. 이 접근 방식을 사용하면 헤더와 푸터가 동적 요소 그룹을 맥락화하는 유연한 폼을 만들 수 있습니다.
데이터 그룹화를 위해 Section을 사용하는 완전한 프로필 화면 예제를 살펴보겠습니다. 폼에는 세 개의 섹션이 있습니다. 사용자 정보, 개인정보 설정, 통계입니다. 각 섹션은 자체 헤더를 사용하고 마지막 섹션에는 요약 정보가 있는 푸터가 있습니다.
struct ProfileView: View {
@State private var displayName = "Alex Johnson"
@State private var bio = "iOS developer"
@State private var isProfilePublic = true
@State private var showEmail = false
var body: some View {
Form {
Section(header: Text("Profile Info")) {
TextField("Display name", text: $displayName)
TextField("Bio", text: $bio, axis: .vertical)
.lineLimit(3)
}
Section(header: Text("Privacy")) {
Toggle("Public profile", isOn: $isProfilePublic)
Toggle("Show email", isOn: $showEmail)
.disabled(!isProfilePublic)
}
Section(header: Text("Stats"),
footer: Text("Last updated today at 2:30 PM")) {
LabeledContent("Posts", value: "42")
LabeledContent("Followers", value: "1,280")
LabeledContent("Following", value: "346")
}
}
.navigationTitle("Profile")
}
}
세 개의 Section이 기능 영역을 명확하게 구분합니다. 편집 가능한 프로필 필드, 개인정보 토글, 통계입니다. 두 번째 섹션은 유효성 검사를 보여줍니다. “Show email” 토글은 프로필이 공개될 때까지 비활성화됩니다. 세 번째 섹션의 푸터는 마지막 업데이트 시간을 표시합니다. 추가 컨텍스트 정보에 푸터를 사용하는 예입니다. LabeledContent는 Form에서 키-값 쌍을 표시하는 표준 SwiftUI 컴포넌트입니다.
Section(
header: HStack {
Image(systemName: "bell.fill")
.foregroundStyle(.blue)
Text("Notifications")
.font(.headline)
},
footer: Text("Manage push and email alerts")
) {
Toggle("Push notifications", isOn: $push)
Toggle("Email notifications", isOn: $email)
Stepper("Quiet hours: \(quietStart) — \(quietEnd)",
value: $quietStart,
in: 0...23)
}
이 예제는 header가 모든 SwiftUI View가 될 수 있음을 보여줍니다. Image와 Text와 함께 HStack을 사용하면 헤더 옆에 아이콘이 추가되어 섹션이 시각적으로 더 표현력 있게 됩니다. 사용자 정의 헤더는 인터페이스에서 중요한 섹션(알림 설정, 유료 기능 또는 경고가 있는 섹션)을 강조하는 데 유용합니다. 그러나 사용자 정의 헤더를 과도하게 사용하는 것은 권장되지 않습니다. 인터페이스 일관성을 유지하기 위해 화면당 1-2개의 비표준 스타일 섹션이면 충분합니다.
자주 묻는 질문
아니요, Section은 SwiftUI에서 중첩을 지원하지 않습니다. Section을 다른 Section 안에 넣으려고 하면 컴파일 오류가 발생합니다. 계층적 그룹화를 위해서는 Section 내에서 List를 OutlineGroup 또는 DisclosureGroup과 함께 사용하세요.
Section 간 간격은 시스템에 의해 관리되며 패딩 수정자를 통해 변경할 수 없습니다. iOS에서 섹션 간 거리는 16-20포인트이며 HIG를 따릅니다. 간격에 영향을 미치는 유일한 방법은 사용자 정의 ListStyle을 사용하는 것이지만 권장되지 않습니다.
Group은 시각적 스타일링 없이 요소를 그룹화하는 보이지 않는 컨테이너입니다. Section은 헤더, 푸터, 간격 및 시각적 블록을 추가합니다. Group은 조건부 렌더링에 사용되고 Section은 인터페이스 구조화에 사용됩니다.
네, Section은 자동으로 접근성 레이블을 추가합니다. 섹션 헤더는 그룹의 접근성 헤더가 되고 푸터는 접근성 힌트가 됩니다. VoiceOver는 섹션에 들어가기 전에 헤더를 읽어 장애가 있는 사용자의 탐색을 개선합니다.
아니요, Section은 Form 또는 List 내에서만 작동합니다. 이러한 컨테이너 외부에서 Section을 사용하면 컴파일 오류가 발생합니다. VStack이나 ScrollView에서 요소를 그룹화하려면 Group 또는 수동 간격 구성이 있는 사용자 정의 View를 사용하세요.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.