如何在开启Reduce Motion时禁用SwiftUI视图过渡动画
SwiftUI适配Reduce Motion模式的过渡动画问题
问题场景
我的App中有ContinueView视图,点击按钮会滑出视野。现在需要为开启Reduce Motion的用户提供支持:不使用滑动动画,直接显示/隐藏视图。已经在ContentView中声明了@Environment(\.accessibilityReduceMotion) var isReducedMotion环境变量,但尝试传nil给transition时报错:'nil' cannot be used in context expecting type 'AnyTransition'。
当前实现代码
ContentView 代码
struct ContentView: View { @Environment(\.accessibilityReduceMotion) var isReducedMotion @State private var hasRequestedNotifications = UserDefaults.standard.bool(forKey: "hasRequestedNotifications") @State private var isShowingContinueView = !UserDefaults.standard.bool(forKey: "isLoggedIn") var body: some View { // ... 其他视图代码 if isShowingContinueView { ContinueView(isShowingContinueView: $isShowingContinueView) .transition(.asymmetric( insertion: AnyTransition.move(edge: .trailing).combined(with: .opacity), removal: AnyTransition.move(edge: .leading).combined(with: .opacity) )) } else if !hasRequestedNotifications { AllowNotificationsView(hasRequestedNotifications: $hasRequestedNotifications) .transition(.asymmetric( insertion: AnyTransition.move(edge: .trailing).combined(with: .opacity), removal: AnyTransition.move(edge: .leading).combined(with: .opacity) )) } // ... 其他视图代码 } }
ContinueView 按钮逻辑
Button("Continue") { withAnimation { self.isShowingContinueView.wrappedValue = false } }
错误尝试方案
尝试通过isReducedMotion控制过渡动画,但因传入nil报错:
ContinueView(isShowingContinueView: $isShowingContinueView) .transition(isReducedMotion ? nil : .asymmetric( insertion: AnyTransition.move(edge: .trailing).combined(with: .opacity), removal: AnyTransition.move(edge: .leading).combined(with: .opacity) ))
解决方法
SwiftUI中transition不接受nil,可以用AnyTransition.identity替代——这是一个无任何动画效果的过渡,视图会直接显示/隐藏,符合Reduce Motion的需求。
修改后的代码
1. 更新ContentView中的过渡设置
if isShowingContinueView { ContinueView(isShowingContinueView: $isShowingContinueView) .transition(isReducedMotion ? .identity : .asymmetric( insertion: AnyTransition.move(edge: .trailing).combined(with: .opacity), removal: AnyTransition.move(edge: .leading).combined(with: .opacity) )) } else if !hasRequestedNotifications { AllowNotificationsView(hasRequestedNotifications: $hasRequestedNotifications) .transition(isReducedMotion ? .identity : .asymmetric( insertion: AnyTransition.move(edge: .trailing).combined(with: .opacity), removal: AnyTransition.move(edge: .leading).combined(with: .opacity) )) }
2. 优化ContinueView的按钮动画(可选)
为了彻底适配Reduce Motion,还可以在触发状态变化时,根据isReducedMotion决定是否启用动画:
// 需要先在ContinueView中注入isReducedMotion环境变量 struct ContinueView: View { @Environment(\.accessibilityReduceMotion) var isReducedMotion @Binding var isShowingContinueView: Bool var body: some View { // ... 视图内容 Button("Continue") { withAnimation(isReducedMotion ? nil : .default) { isShowingContinueView = false } } } }
这样,开启Reduce Motion的用户会看到视图直接显隐,关闭时则保留原有的滑动过渡动画。
内容的提问来源于stack exchange,提问作者Amy
相关产品推荐
相关产品推荐

