SwiftUI 中的 Section:是什么,创建部分和分组

作者: IT Sectr 发布日期: 2026-06-25 阅读时间: 7 分钟

SwiftUI 中的 Section 是一个容器组件,用于在 Form 或 List 内部对元素进行逻辑分组。该组件将内容显示为带有系统间距、圆角以及可选头部和底部的可视块。根据 Apple Developer Documentation (2025)Section 不管理数据,只组织呈现:所有子元素继承其样式和间距,确保表单和列表的结构化显示。

要点

  • Section — 用于在 Form 和 List 中对元素进行逻辑分组的容器
  • 头部 Section 以系统字体显示在元素组上方
  • 底部 以较小字体在组下方添加解释性文本
  • ForEach 在 Section 内部允许创建动态组
  • 嵌套部分 支持分层组织内容

什么是 SwiftUI 中的 Section?

Section 是一个 SwiftUI 结构组件,用于在 Form 和 List 容器内对元素进行分组。与 VStack 或 HStack 不同,Section 添加了系统间距、头部和底部,以及在 iOS 上以圆角块形式对组进行视觉突出显示。

Section 不会改变子元素的行为 — 它只组织它们的呈现。Section 内的所有控件 — Picker、Toggle、TextField — 正常工作,但在视觉上被组合成一个逻辑组。这对于表单屏幕尤其重要,用户需要快速浏览输入数据的结构。

系统自动管理各部分之间的间距:iOS 上 Section 之间的距离为 16–20 点,Section 内元素之间的距离为 0(行之间的分隔符)。开发人员无法通过 padding 修改器更改这些间距 — 它们由系统控制以确保统一的外观。

Section 接受两个可选参数:header — 组标题,以及 footer — 组下方的解释性文本。头部以粗体 caption 样式字体显示在部分元素上方,底部以较小的灰色字体显示。两个参数都接受任何 SwiftUI View,而不仅仅是 Text。

Section 的头部帮助用户了解组内元素属于哪个类别。例如,在设置屏幕上,标题「通知」「隐私」和「帐户」立即引导用户。底部适合解释:「在会议期间关闭通知」或「密码必须至少包含 8 个字符」。底部在需要时自动分成多行。

swift
Section(
    header: Text("账户安全"),
    footer: Text("使用至少 8 个字符的强密码。")
) {
    SecureField("Current password", text: $currentPassword)
    SecureField("New password", text: $newPassword)
}

在示例中,Section 有标题「帐户安全」和包含密码安全建议的底部。用户将头部视为部分标签,填写两个字段,并立即阅读它们下方的警告。这种结构改善了用户体验,因为关于该部分的所有信息都在一个屏幕上,无需单独的帮助。

Form 和 List 中的 Section

Section 在 Form 和 List 内部都能工作,但视觉表示不同。在 Form 中,Section 显示为具有圆角和系统背景的块,通过间距与相邻部分分开。在 List 中,Section 可以使用 plain 样式 — 无背景和圆角,或 inset-grouped — 带圆角块,类似于 Form。

容器的选择影响 Section 的样式。将具有相同内容的 Section 放置在 Form 和具有 .insetGrouped 样式的 List 中将产生相同的结果。然而,Form 添加系统间距并默认使用 grouped 样式,而 List 需要通过修改器 .listStyle(.insetGrouped) 显式指定样式。

容器默认 Section可用样式
FormInsetGrouped 带圆角.grouped(仅 Form)
ListPlain — 无部分背景.plain, .inset, .insetGrouped, .sidebar

要在 List 中实现相同的外观,请使用 .listStyle(.insetGrouped)。此样式模仿 Form 的外观,适用于基于 List 构建的设置屏幕。对于标准数据列表,使用 .plain — 无部分高亮,行之间带有细分隔符。

通过 ForEach 实现动态内容

Section 可以通过 ForEach 包含动态数量的元素。这允许创建具有重复元素的组,同时保持整个组的头部和底部。Section 内部的 ForEach 遍历数据集合并为每个元素创建子 View,而不会破坏部分结构。

动态部分对于具有可变数量选项的设置屏幕非常有用:可供选择的语言列表、连接的设备列表或推送订阅列表。部分的头部保持静态,而内容根据数据而变化。

swift
struct DynamicSectionView: View {
    let categories = ["Work", "Personal", "Finance", "Health"]
    @State private var selected = Set<String>()

    var body: some View {
        Form {
            Section(header: Text("分类"),
                    footer: Text("选择您偏好的分类")) {
                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.count) 个分类")
                    .foregroundStyle(.secondary)
            }
        }
    }
}

在此示例中,ForEach 为数组 categories 中的每个类别生成一个 Toggle。部分的头部和底部设置一次并适用于整个组。第二部分显示所选类别的数量 — 不依赖 ForEach 并保持静态。这种方法允许创建灵活的表单,其中头部和底部为动态元素组提供上下文。

Section 代码示例

让我们来看一个完整的个人资料屏幕示例,使用 Section 对数据进行分组。表单包含三个部分:用户信息、隐私设置和统计信息。每个部分使用自己的头部,最后一个部分使用带有摘要信息的底部。

swift
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("个人资料")) {
                TextField("Display name", text: $displayName)
                TextField("Bio", text: $bio, axis: .vertical)
                    .lineLimit(3)
            }

            Section(header: Text("隐私")) {
                Toggle("Public profile", isOn: $isProfilePublic)
                Toggle("Show email", isOn: $showEmail)
                    .disabled(!isProfilePublic)
            }

            Section(header: Text("统计"),
                    footer: Text("最后更新于今天 14:30")) {
                LabeledContent("Posts", value: "42")
                LabeledContent("Followers", value: "1,280")
                LabeledContent("Following", value: "346")
            }
        }
        .navigationTitle("Profile")
    }
}

三个 Section 清晰地区分了功能块:可编辑的个人资料字段、隐私开关和统计信息。第二部分演示了验证:Toggle「显示电子邮件」在个人资料公开之前处于禁用状态。第三部分的底部显示最后更新时间 — 使用底部提供额外上下文信息的示例。LabeledContent 是 Form 中显示「键-值」对的标准 SwiftUI 组件。

带自定义头部的 Section

swift
Section(
    header: HStack {
        Image(systemName: "bell.fill")
            .foregroundStyle(.blue)
        Text("通知")
            .font(.headline)
    },
    footer: Text("管理推送和电子邮件通知")
) {
    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 可以互相嵌套吗?

不行,Section 在 SwiftUI 中不支持嵌套。尝试将一个 Section 放入另一个 Section 会导致编译错误。对于层次分组,请在 Section 内部使用带有 OutlineGroup 或 DisclosureGroup 的 List

如何更改 Section 之间的间距?

Section 之间的间距由系统管理,不能通过 padding 修改器更改。在 iOS 上,各部分之间的距离为 16–20 点,并符合 HIG。影响间距的唯一方法是使用自定义 ListStyle,但这不推荐。

Section 与 Group 在 SwiftUI 中有什么不同?

Group 是一个不可见的容器,用于在无视觉格式的情况下对元素进行分组。Section 添加了头部、底部、间距和视觉块。Group 用于条件渲染,Section 用于结构化界面。

Section 支持无障碍功能吗?

是的,Section 自动添加无障碍标签。部分的头部成为组的无障碍标签,底部成为无障碍提示。VoiceOver 在进入部分之前会读取头部,这改善了导航对于残障用户的体验。

Section 可以在没有 Form 或 List 的情况下使用吗?

不行,Section 只在 Form 或 List 内部工作。在这些容器之外使用 Section 会导致编译错误。要在 VStack 或 ScrollView 中对元素进行分组,请使用 Group 或手动设置间距的自定义 View。

总结

  • Section — 用于在 Form 和 List 中对元素进行分组并带有系统间距的容器
  • Headerfooter — 用于关于组的上下文信息的可选参数
  • ForEach 在 Section 内部允许创建具有重复元素的动态组
  • 嵌套 Section 被禁止 — 对于子组请使用 DisclosureGroup
  • 样式 Section 取决于容器:Form 默认使用 insetGrouped,List 使用 plain
  • 自定义 header 可以是任何带有图标和自定义字体的 SwiftUI View
  • 使用 Section 对输入字段和设置进行逻辑分组

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读