在 SwiftUI 中,Environment
和 Environment Values
(环境值)提供了一种机制,帮助开发者在整个视图层次结构中轻松共享数据。环境值是 SwiftUI 内置的全局设置,允许我们在不同视图层级中访问和动态调整系统属性。
系统内置 #
以下是 SwiftUI 支持的主要分类和常见值的表格说明。
1. 颜色和主题 #
属性名 | 类型 | 描述 | 版本要求 |
---|---|---|---|
colorScheme | ColorScheme | 当前的浅色模式(.light )或深色模式(.dark )。 | iOS 13+ / macOS 10.15+ |
colorSchemeContrast | ColorSchemeContrast | 当前颜色主题的对比度设置(.standard 或 .increased )。 | iOS 14+ / macOS 11+ |
accentColor | Color? | 当前界面的默认强调颜色(已被 tint 替代)。 | iOS 13+ / macOS 10.15+ |
tint | Color? | 当前界面控件的默认主题色(推荐使用,替代 accentColor )。 | iOS 15+ / macOS 12+ |
2. 布局与尺寸 #
属性名 | 类型 | 描述 | 版本要求 |
---|---|---|---|
layoutDirection | LayoutDirection | 当前布局方向(.leftToRight 或 .rightToLeft ,用于支持多种语言)。 | iOS 13+ / macOS 10.15+ |
sizeCategory | ContentSizeCategory | 当前的动态字体大小设置(支持辅助功能,如 .large , .extraLarge )。 | iOS 13+ / macOS 10.15+ |
defaultMinListRowHeight | CGFloat | 列表中每一行的最小高度。 | iOS 13+ / macOS 10.15+ |
defaultMinListHeaderHeight | CGFloat | 列表头部(Section Header)的最小高度。 | iOS 13+ / macOS 10.15+ |
pixelLength | CGFloat | 一个逻辑点单位对应的像素值(在屏幕坐标中);用于高 DPI 的屏幕适配。 | iOS 14+ / macOS 11+ |
windowSize | CGSize | 获取窗口当前的实际尺寸(适用于 macOS 和 iPadOS 多窗口应用)。 | iOS 16+ / macOS 13+ |
3. 动画与交互 #
属性名 | 类型 | 描述 | 版本要求 |
---|---|---|---|
transaction | Transaction | 当前动画事务的对象,控制视图更新时的动画行为。 | iOS 13+ / macOS 10.15+ |
isEnabled | Bool | 如果当前交互状态禁用,则环境中的 isEnabled 会为 false (如在按钮状态下)。 | iOS 15+ / macOS 12+ |
controlActiveState | ControlActiveState | 当前控件是否处于激活状态(如 .key , .active , .inactive )。 | iOS 13+ / macOS 10.15+ |
4. 可访问性(Accessibility) #
属性名 | 类型 | 描述 | 版本要求 |
---|---|---|---|
accessibilityEnabled | Bool | 当前是否启用了辅助功能(如 VoiceOver)。 | iOS 13+ / macOS 10.15+ |
reduceMotion | Bool | 查询用户是否在系统中启用了「减少动态效果」。 | iOS 13+ / macOS 10.15+ |
reduceTransparency | Bool | 用户是否启用了「减少透明度」。 | iOS 13+ / macOS 10.15+ |
accessibilityInvertColors | Bool | 是否启用了「反转颜色」的辅助功能。 | iOS 13+ / macOS 10.15+ |
buttonShape | Bool | 用户是否启用了「显示按钮形状」选项(适用于按钮的可视化提示)。 | iOS 13+ / macOS 10.15+ |
5. 本地化与语言 #
属性名 | 类型 | 描述 | 版本要求 |
---|---|---|---|
layoutDirection | LayoutDirection | 当前语言对应的布局方向(如从左到右 LTR ,或从右到左 RTL )。 | iOS 13+ / macOS 10.15+ |
locale | Locale | 当前应用使用的本地化语言设置。 | iOS 13+ / macOS 10.15+ |
calendar | Calendar | 当前系统所使用的日历(如公历或阴历)。 | iOS 13+ / macOS 10.15+ |
timeZone | TimeZone | 当前的系统时区设置。 | iOS 13+ / macOS 10.15+ |
6. 滚动与导航 #
属性名 | 类型 | 描述 | 版本要求 |
---|---|---|---|
scrollViewContentOffset | CGPoint | 表示 ScrollView 的滚动偏移量。 | iOS 16+ / macOS 13+ |
navigationBarHidden | Bool | 是否隐藏导航栏。 | iOS 13+ / macOS 10.15+ |
navigationBarBackButtonHidden | Bool | 是否隐藏导航栏的返回按钮。 | iOS 13+ / macOS 10.15+ |
7. 设备和系统行为 #
属性名 | 类型 | 描述 | 版本要求 |
---|---|---|---|
deviceSupportsHaptics | Bool | 查询当前设备是否支持 Haptic 触觉反馈(如震动效果)。 | iOS 13+ / macOS 10.15+ |
deviceSupportsMultitasking | Bool | 判断是否支持多任务窗口(iPad 的 SlideOver 或 SplitView)。 | iOS 14+ / macOS 11+ |
scenePhase | ScenePhase | 检测当前 App 的场景状态:如 .active (活跃)、.inactive (暂停)或 .background (后台)。 | iOS 14+ / macOS 11+ |
8. 输入法与键盘 #
属性名 | 类型 | 描述 | 版本要求 |
---|---|---|---|
keyboardType | UIKeyboardType | 表示当前输入框的键盘类型(数字键盘、邮件键盘等)。 | iOS 13+ / macOS 10.15+ |
keyboardHidden | Bool | 当前是否隐藏键盘状态。 | iOS 15+ / macOS 12+ |
textInputAutocapitalization | TextInputAutocapitalization | 当前输入框中的自动大写状态。 | iOS 15+ / macOS 12+ |
总结 #
SwiftUI 中的Environment Values
主要分类包括以下:
- 颜色和主题(
colorScheme
,tint
等) - 布局与尺寸(
sizeCategory
,layoutDirection
等) - 动画与交互(
isEnabled
,transaction
等) - 可访问性支持(
reduceMotion
,accessibilityInvertColors
等) - 本地化与语言支持(
locale
,calendar
,timeZone
等) - 滚动与导航(
scrollViewContentOffset
,navigationBarHidden
等) - 设备与系统行为(
scenePhase
,deviceSupportsHaptics
等) - 输入法和键盘(
keyboardType
,textInputAutocapitalization
等)
通过 @Environment
,你可以优雅地获取和设置这些全局环境值,在视图层级中实现动态行为和响应式设计。
如何自定义 Environment Values
#
可直接使用官方提供的
@Entry
,下面的方案应该是老版本。
在 SwiftUI 中,@Environment
用于访问和传递全局或层级共享的数据。虽然 SwiftUI 内置了许多环境变量(如颜色方案、布局方向等),但开发者也可以自定义环境变量,实现跨视图层级共享数据。以下是详细的使用方法和示例:
核心步骤 #
1. 定义环境键(EnvironmentKey) #
通过 EnvironmentKey
协议定义自定义环境变量的默认值:
// 定义环境键
private struct CustomThemeKey: EnvironmentKey {
static let defaultValue: Color = .blue // 默认颜色为蓝色
}
2. 扩展 EnvironmentValues #
将自定义变量添加到 EnvironmentValues
中,使其可通过 \.customTheme
访问:
extension EnvironmentValues {
var customTheme: Color {
get { self[CustomThemeKey.self] }
set { self[CustomThemeKey.self] = newValue }
}
}
3. 在视图中使用 @Environment #
通过 @Environment
属性包装器读取或修改环境变量:
struct ChildView: View {
@Environment(\.customTheme) private var themeColor // 读取环境变量
var body: some View {
Text("子视图")
.foregroundStyle(themeColor) // 应用环境变量
}
}
4. 设置环境变量值 #
在父视图中使用 .environment(_:_:)
修饰符设置环境变量的值:
struct ParentView: View {
var body: some View {
ChildView()
.environment(\.customTheme, .red) // 覆盖默认值为红色
}
}
完整代码示例 #
import SwiftUI
// 步骤1:定义环境键
private struct CustomThemeKey: EnvironmentKey {
static let defaultValue: Color = .blue
}
// 步骤2:扩展 EnvironmentValues
extension EnvironmentValues {
var customTheme: Color {
get { self[CustomThemeKey.self] }
set { self[CustomThemeKey.self] = newValue }
}
}
// 步骤3:子视图读取环境变量
struct ChildView: View {
@Environment(\.customTheme) private var themeColor
var body: some View {
VStack {
Text("当前主题颜色")
.font(.title)
.foregroundStyle(themeColor)
Divider()
GrandchildView()
}
}
}
// 孙视图(继承父视图的环境变量)
struct GrandchildView: View {
@Environment(\.customTheme) private var themeColor
var body: some View {
Button("按钮") {}
.padding()
.background(themeColor)
.foregroundStyle(.white)
.cornerRadius(10)
}
}
// 步骤4:父视图设置环境变量
struct ParentView: View {
var body: some View {
VStack {
// 默认环境变量(蓝色)
ChildView()
Divider()
// 自定义环境变量(红色)
ChildView()
.environment(\.customTheme, .red)
}
}
}
// 预览
#Preview {
ParentView()
}
使用场景 #
- 主题管理:全局颜色、字体等样式的统一配置。
- 功能开关:控制某些功能是否启用(如深色模式、实验性功能)。
- 用户配置:传递用户设置(如语言、时区)。
- 依赖注入:共享服务或数据模型(如网络请求层、数据库上下文)。
与 @State 和 @ObservedObject 的区别 #
特性 | @Environment | @State / @ObservedObject |
---|---|---|
作用范围 | 跨视图层级传递 | 当前视图或其子视图 |
数据共享性 | 全局或局部共享 | 通常局限于单一视图树分支 |
适用场景 | 配置、主题、全局状态 | 视图内部状态或临时数据 |
修改方式 | 通过 .environment() 覆盖 | 直接修改或绑定 |
高级用法 #
动态修改环境变量 #
结合 @State
动态更新环境变量:
struct ParentView: View {
@State private var dynamicColor: Color = .green
var body: some View {
VStack {
ChildView()
.environment(\.customTheme, dynamicColor)
Button("切换颜色") {
dynamicColor = [.red, .green, .blue].randomElement()!
}
}
}
}
自定义对象作为环境变量 #
传递复杂对象(需符合 ObservableObject
):
// 定义可观察对象
class AppSettings: ObservableObject {
@Published var isDarkMode: Bool = false
}
// 定义环境键
private struct AppSettingsKey: EnvironmentKey {
static let defaultValue = AppSettings()
}
// 扩展 EnvironmentValues
extension EnvironmentValues {
var appSettings: AppSettings {
get { self[AppSettingsKey.self] }
set { self[AppSettingsKey.self] = newValue }
}
}
// 使用
struct ContentView: View {
@Environment(\.appSettings) private var settings
var body: some View {
Toggle("深色模式", isOn: $settings.isDarkMode)
}
}
注意事项 #
- 作用域控制:环境变量会向下传递到所有子视图,确保在合适的层级设置。
- 性能优化:避免在环境变量中存储频繁变化的大数据。
- 类型安全:确保环境键的
Value
类型与使用处一致。 - 默认值:始终为环境键提供合理的默认值,避免意外崩溃。
通过自定义 @Environment
变量,你可以优雅地在 SwiftUI 应用中管理全局状态,减少显式参数传递,提升代码的可维护性和灵活性。