SwiftUI
Environment Values
深入理解 SwiftUI 的 Environment Values,掌握数据在视图层级中的传递、读取与自定义方法。
Environment Values 是 SwiftUI 中用于在视图层级间向下传递数据的一种高效机制。它允许父视图将配置信息、样式设置或全局状态隐式地传递给所有子视图,而无需通过初始化参数逐层显式传递。
核心概念
- EnvironmentValues: 一个包含所有环境值的容器结构体。SwiftUI 预定义了许多标准值(如
colorScheme,font,locale),同时也支持自定义扩展。 - @Environment: 用于在视图中读取环境值的属性包装器。当环境值发生变化时,依赖该值的视图会自动刷新。
- EnvironmentKey: 用于定义自定义环境值的键,必须遵循
EnvironmentKey协议并提供默认值。 - Modifier: 使用
.environment(_:_:)或专用修饰符(如.font(),.foregroundStyle())来设置环境值。
读取环境值
使用 @Environment 属性包装器,通过 KeyPath 读取特定的环境值。
import SwiftUI
struct ContentView: View {
// 读取系统的配色方案
@Environment(\.colorScheme) var colorScheme
// 读取系统的语言环境
@Environment(\.locale) var locale
var body: some View {
VStack {
Text("当前模式: \(colorScheme == .dark ? "深色" : "浅色")")
Text("当前语言: \(locale.identifier)")
}
}
}设置环境值
1. 使用专用修饰符(推荐)
SwiftUI 为常用的环境值提供了专用的视图修饰符,代码更具可读性。
VStack {
Text("Hello World")
}
.font(.title) // 设置字体环境值
.foregroundStyle(.blue) // 设置前景色环境值
.lineLimit(2) // 设置行数限制2. 使用 .environment 修饰符
对于没有专用修饰符的环境值,或自定义环境值,使用 .environment(_:_:)。
VStack {
Text("Custom Environment")
}
.environment(\.layoutDirection, .rightToLeft) // 强制从右向左布局3. 使用 .transformEnvironment 修饰符
当你需要基于父视图传递下来的环境值进行修改时,使用 .transformEnvironment。
VStack {
Text("Transformed Environment")
}
.transformEnvironment(\.font) { font in
// 如果父视图设置了字体,将其改为等宽字体,否则使用默认等宽字体
font = font?.monospaced()
}自定义 Environment Values
使用 Entry 宏 (iOS 18+, Swift 6)
在最新的 Swift 版本中,可以使用 @Entry 宏大大简化自定义环境值的定义。
import SwiftUI
extension EnvironmentValues {
// 定义一个名为 themeColor 的自定义环境值,默认值为 .black
@Entry var themeColor: Color = .black
}
struct CustomView: View {
@Environment(\.themeColor) var themeColor
var body: some View {
Text("Theme Color")
.foregroundStyle(themeColor)
}
}
#Preview {
CustomView()
.environment(\.themeColor, .purple) // 注入自定义值
}传统方式(EnvironmentKey)
在旧版本中,需要手动遵循 EnvironmentKey 协议。
private struct ThemeColorKey: EnvironmentKey {
static let defaultValue: Color = .black
}
extension EnvironmentValues {
var themeColor: Color {
get { self[ThemeColorKey.self] }
set { self[ThemeColorKey.self] = newValue }
}
}常用 Environment Values 分类
显示与布局(Display & Layout)
\.colorScheme: 当前的配色方案(.light或.dark)。\.pixelLength: 屏幕上一个物理像素对应的逻辑长度。\.displayScale: 当前屏幕的显示缩放因子(如 2.0, 3.0)。\.horizontalSizeClass: 水平方向的尺寸类别(.compact或.regular)。\.verticalSizeClass: 垂直方向的尺寸类别。\.layoutDirection: 布局方向(.leftToRight或.rightToLeft)。
文本与排版(Text & Typography)
\.font: 当前的字体配置。\.lineLimit: 文本的最大行数限制。\.minimumScaleFactor: 文本缩小的最小比例。\.multilineTextAlignment: 多行文本的对齐方式。\.truncationMode: 文本截断模式(头部、中间、尾部)。\.lineSpacing: 行间距。\.allowsTightening: 是否允许文本紧缩以适应空间。
交互与动作 (Actions)
SwiftUI 提供了一些作为函数的环境值,用于执行特定动作。
\.openURL: 打开一个 URL。@Environment(\.openURL) var openURL // 调用: openURL(URL(string: "https://apple.com")!)\.dismiss: 关闭当前呈现的视图(如 Sheet 或 Popover)。@Environment(\.dismiss) var dismiss // 调用: dismiss()\.refresh: 触发刷新操作(配合.refreshable使用)。
控件状态 (Controls)
\.isEnabled: 视图及其子视图是否处于启用状态。\.controlSize: 控件的尺寸规格(.mini,.small,.regular,.large,.extraLarge)。\.editMode: 当前的编辑模式状态(.active,.inactive)。
辅助功能 (Accessibility)
\.accessibilityEnabled: 辅助功能是否开启。\.accessibilityReduceMotion: 用户是否开启了“减弱动态效果”。\.accessibilityDifferentiateWithoutColor: 是否开启了“不以颜色区分”。\.legibilityWeight: 字体粗细偏好(如.bold)。
国际化与地区 (Locale & Region)
\.locale: 当前的语言环境设置。\.calendar: 当前使用的日历。\.timeZone: 当前时区。
最佳实践
- 优先使用专用修饰符: 如
.font(.headline)优于.environment(\.font, .headline),前者更简洁且可能有内部优化。 - 层级传递: 环境值会一直向下传递,直到被子视图覆盖。利用这一特性可以轻松实现全局主题或配置。
- 避免过度使用: 虽然环境值很方便,但过度依赖会使视图的数据来源变得隐晦。对于紧密耦合的数据,仍建议使用初始化参数传递。
- 性能考量: 修改高层级的环境值会触发整个子树的重绘,应尽量在需要的最小范围内修改环境值。
在 GitHub 上编辑
上次更新于