@Environment(\.accessibilityReduceMotion) 是 SwiftUI 提供的一个环境值,表示用户是否在设备的 设置 > 辅助功能 > 动态效果 > 减弱动态效果 中启用了“减弱动态效果”选项。
这个选项通常用于帮助用户减弱由于动画或快速视觉变化带来的不适,例如眩晕或注意力分散。当该选项启用时,accessibilityReduceMotion 的值为 true,开发者可以利用此值调整或禁用某些动画。
如何使用 accessibilityReduceMotion
以下是一些常见的使用场景和代码示例:
示例 1:动态调整动画
如果用户启用了“减弱动态效果”,则禁用动画或切换到更简单的过渡效果:
struct ContentView: View {
@Environment(\.accessibilityReduceMotion) var reduceMotion
@State private var isToggled = false
var body: some View {
VStack {
Toggle("切换状态", isOn: $isToggled)
.padding()
Rectangle()
.fill(isToggled ? Color.green : Color.red)
.frame(width: 100, height: 100)
.animation(
reduceMotion ? nil : .easeInOut(duration: 0.5),
value: isToggled
)
}
.padding()
}
}
当 reduceMotion 为 true 时,动画被禁用。
当 reduceMotion 为 false 时,正常执行过渡动画。
示例 2:替代动态效果
在减弱动态效果模式下,用更直接的视觉变化替代动画。例如,直接切换视图位置,而不是使用平滑移动。
struct ContentView: View {
@Environment(\.accessibilityReduceMotion) var reduceMotion
@State private var offset: CGFloat = 0
var body: some View {
VStack {
Button("移动") {
offset += 50
}
.padding()
Circle()
.fill(Color.blue)
.frame(width: 50, height: 50)
.offset(x: offset) // 直接跳转到目标位置
.animation(
reduceMotion ? nil : .spring(),
value: offset
)
}
}
}
当 reduceMotion 为 false 时,正常执行过渡动画。
当 reduceMotion 为 false 时,正常执行过渡动画。
测试方式
1、在设备或模拟器上,打开 设置 > 辅助功能 > 动态效果。
2、启用 减弱动态效果。
3、运行应用,观察动画是否根据设置正确调整。
总结
@Environment(\.accessibilityReduceMotion) 帮助开发者响应用户的辅助功能设置,减弱动态效果。
使用时可以动态调整动画、转场效果,或禁用复杂的视觉效果。
始终测试以确保用户体验在启用和禁用减弱动态效果时都符合预期。
扩展知识
自定义函数 withOptionalAnimation
可以使用自定义函数 withOptionalAnimation,更加便捷的根据动态效果自动调整动画行为。用于根据用户的“减弱动态效果”设置,选择性地应用动画效果。
func withOptionalAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
if UIAccessibility.isReduceMotionEnabled {
return try body()
} else {
return try withAnimation(animation, body)
}
}
参数解释:
animation: Animation?:动画类型,可选,默认为 SwiftUI 的默认动画 (.default)。
body: () throws -> Result:一个执行动画相关逻辑的闭包。
返回值:该函数的返回值取决于 body 的执行结果。
功能:
使用系统的 辅助功能设置 (UIAccessibility.isReduceMotionEnabled) 检查用户是否启用了“减弱动态效果”。
如果启用了减弱动态效果 (true),则直接执行 body,不添加动画。
如果未启用减弱动态效果 (false),则通过 withAnimation 包裹 body,应用指定的动画。
工作原理总结
1、UIAccessibility.isReduceMotionEnabled:检查用户是否启用了“减弱动态效果”。
true:跳过动画。
false:使用动画过渡。
2、withOptionalAnimation:封装了这一逻辑,统一管理是否应用动画的行为。
3、用户体验优化:
对于未启用“减弱动态效果”的用户,按钮点击会触发带有动画的缩放效果。
对于启用“减弱动态效果”的用户,缩放会直接发生,避免动画对敏感用户造成不适。
代码示例:
struct ContentView: View {
@Environment(\.accessibilityReduceMotion) var reduceMotion
@State private var scale = 1.0
func withOptionalAnimation<Result>(_ animation: Animation? = .default, _ body: () throws -> Result) rethrows -> Result {
if UIAccessibility.isReduceMotionEnabled {
return try body()
} else {
return try withAnimation(animation, body)
}
}
var body: some View {
Button("Hello, World!") {
withOptionalAnimation {
scale *= 1.5
}
}
.scaleEffect(scale)
}
}
用户未启用了“减弱动态效果”,应用会触发带有动画的缩放效果。
用户启用了“减弱动态效果”,缩放会直接变为1.5。
代码的实际应用场景
1、辅助功能支持:尊重用户偏好,自动调整动画行为。
2、代码复用:通过 withOptionalAnimation 抽象出动画逻辑,简化代码结构,使得相同逻辑可以在多个地方复用。
3、动画与无动画共存:确保应用在支持动画和减弱动画两种场景下,都能正确运行。
参考文章
Supporting specific accessibility needs with SwiftUI:https://www.hackingwithswift.com/books/ios-swiftui/supporting-specific-accessibility-needs-with-swiftui