View Styles
全面解析 SwiftUI 的视图样式系统,涵盖按钮、开关、列表等组件的内置样式及自定义样式的实现方法。
概述
SwiftUI 提供了一套强大的样式系统,允许开发者通过简单的修饰器改变视图的外观和行为。大多数标准控件(如 Button、Toggle、List)都遵循特定的样式协议。
使用样式的好处:
- 一致性:确保应用内组件风格统一。
- 上下文适应:系统会根据平台(iOS, macOS, tvOS, watchOS)和环境自动调整默认样式。
- 可复用性:自定义样式可以轻松复用于多个视图。
基本用法是使用 .style() 修饰器,例如 .buttonStyle(.bordered)。这些修饰器通常会向下传递,影响层级中的所有同类视图。
控件样式(Control Styles)
ButtonStyle
用于自定义 Button 的外观和交互反馈。
VStack(spacing: 20) {
Button("Automatic") {}
.buttonStyle(.automatic)
Button("Bordered") {}
.buttonStyle(.bordered)
Button("Bordered Prominent") {}
.buttonStyle(.borderedProminent)
Button("Borderless") {}
.buttonStyle(.borderless)
Button("Plain") {}
.buttonStyle(.plain)
}ToggleStyle
用于 Toggle 开关的样式。
VStack {
Toggle("Switch", isOn: .constant(true))
.toggleStyle(.switch)
Toggle("Button", isOn: .constant(true))
.toggleStyle(.button)
}PickerStyle
用于 Picker 选择器的样式。
Picker("Flavor", selection: .constant("Chocolate")) {
Text("Chocolate").tag("Chocolate")
Text("Vanilla").tag("Vanilla")
}
.pickerStyle(.segmented) // 或 .menu, .wheel, .inline, .navigationLinkMenuStyle
用于 Menu 视图的样式。
Menu("Options") {
Button("Edit") {}
Button("Delete") {}
}
.menuStyle(.button) // 默认样式,通常表现为按钮GaugeStyle
用于 Gauge 仪表盘的样式。
Gauge(value: 0.5) {
Text("Level")
}
.gaugeStyle(.accessoryCircular) // 或 .linearCapacity, .accessoryLinearProgressViewStyle
用于 ProgressView 进度条的样式。
VStack {
ProgressView()
.progressViewStyle(.circular)
ProgressView(value: 0.5)
.progressViewStyle(.linear)
}LabelStyle
用于 Label(图标+文本)的样式。
Label("Favorite", systemImage: "star.fill")
.labelStyle(.titleOnly) // 或 .iconOnly, .titleAndIcon输入样式(Input Styles)
TextFieldStyle
用于 TextField 的样式。
TextField("Username", text: .constant(""))
.textFieldStyle(.roundedBorder) // 或 .plain, .automaticTextEditorStyle
用于 TextEditor 多行文本输入的样式。
TextEditor(text: .constant("Enter bio..."))
.textEditorStyle(.plain) // 或 .automaticLabeledContentStyle
用于 LabeledContent 的样式,常用于表单中显示键值对。
LabeledContent("Version", value: "1.0.0")
.labeledContentStyle(.automatic)容器与布局样式(Container & Layout Styles)
ListStyle
用于 List 的样式,不同平台默认值不同。
List {
Text("Item 1")
Text("Item 2")
}
.listStyle(.insetGrouped) // 或 .plain, .grouped, .inset, .sidebarTableStyle
用于 Table (主要在 macOS/iPadOS) 的样式。
Table(items) {
TableColumn("Name", value: \.name)
}
.tableStyle(.inset) // 或 .borderedTabViewStyle
用于 TabView 的样式。
TabView {
Text("Tab 1").tabItem { Text("1") }
}
.tabViewStyle(.page) // 或 .automatic (底部标签栏)GroupBoxStyle
用于 GroupBox 的样式。
GroupBox(label: Text("Settings")) {
Toggle("Enable", isOn: .constant(true))
}
.groupBoxStyle(.automatic)ControlGroupStyle
用于 ControlGroup 的样式。
ControlGroup {
Button("A") {}
Button("B") {}
}
.controlGroupStyle(.navigation) // 或 .automaticFormStyle
用于 Form 的样式。
Form {
// fields
}
.formStyle(.grouped) // 或 .columnsDisclosureGroupStyle
用于 DisclosureGroup (折叠面板) 的样式。
DisclosureGroup("Details") {
Text("Hidden content")
}
.disclosureGroupStyle(.automatic)IndexViewStyle
用于 List 或 TabView (page style) 的索引视图样式。
TabView {
// pages
}
.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))导航样式(Navigation Styles)
NavigationSplitViewStyle
用于 NavigationSplitView 的样式。
NavigationSplitView {
List(items, selection: $selected) { item in
NavigationLink(item.name, value: item)
}
} detail: {
Text("Detail")
}
.navigationSplitViewStyle(.balanced) // 或 .prominentDetail, .automaticNavigationViewStyle 已被废弃,建议使用 NavigationStack 和 NavigationSplitView 及其对应样式。
自定义样式(Custom Styles)
你可以通过遵循相应的样式协议(如 ButtonStyle)并实现 makeBody(configuration:) 方法来创建自定义样式。
自定义 ButtonStyle
ButtonStyle 的 configuration 提供 label (视图) 和 isPressed (布尔值)。
struct PressableButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding()
.background(Color.blue)
.foregroundColor(.white)
.clipShape(RoundedRectangle(cornerRadius: 8))
.scaleEffect(configuration.isPressed ? 0.95 : 1.0) // 按下缩放效果
.animation(.easeOut(duration: 0.2), value: configuration.isPressed)
}
}
// 使用
Button("Press Me") {}
.buttonStyle(PressableButtonStyle())自定义 ToggleStyle
ToggleStyle 的 configuration 提供 label (视图), isOn (绑定状态) 和 $isOn (Binding)。
struct CheckboxToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
Image(systemName: configuration.isOn ? "checkmark.square.fill" : "square")
.foregroundColor(configuration.isOn ? .blue : .gray)
.onTapGesture {
configuration.isOn.toggle()
}
configuration.label
}
}
}
// 使用
Toggle("Accept Terms", isOn: $isAccepted)
.toggleStyle(CheckboxToggleStyle())样式环境与层级
样式修饰器会注入到环境变量中,影响子视图。
VStack {
Button("Button 1") {} // 使用 Bordered
HStack {
Button("Button 2") {} // 使用 Bordered
Button("Button 3") {} // 使用 Plain (覆盖)
.buttonStyle(.plain)
}
}
.buttonStyle(.bordered)通过掌握这些样式,你可以快速构建符合平台规范的界面,同时也能灵活定制独特的品牌风格。
上次更新于