SwiftUI:禁用默认动画后如何为fullScreenCover添加自定义动画?
如何为SwiftUI的fullScreenCover添加自定义动画?
你提到的transaction.disablesAnimations = true确实会全局禁用所有动画,这就是自定义动画无法生效的核心原因。下面提供两种无需回退到UIKit或使用overlay的方案,直接基于fullScreenCover实现需求:
方案一:iOS 16.4+ 原生支持(推荐)
iOS 16.4及以上版本新增了presentationTransition和dismissalTransition修饰符,可以直接替换fullScreenCover的默认动画,无需手动禁用系统动画:
struct ContentView: View { @State private var isPresentingFullScreenCover = false var body: some View { Button("Show FullScreenCover") { isPresentingFullScreenCover = true } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.black) .fullScreenCover(isPresented: $isPresentingFullScreenCover) { FullScreenCoverView() } // 自定义弹出动画:缩放+淡入 .presentationTransition(.scale.combined(with: .opacity).animation(.easeInOut(duration: 0.5))) // 自定义关闭动画:缩放+淡出 .dismissalTransition(.scale.combined(with: .opacity).animation(.easeInOut(duration: 0.5))) } } struct FullScreenCoverView: View { @Environment(\.dismiss) var dismiss var body: some View { Button("Dismiss") { dismiss() } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.blue) } }
方案二:兼容低版本iOS(iOS 13+)
对于iOS 16.4以下版本,可通过局部禁用系统动画+自定义过渡动画的方式实现:
struct ContentView: View { @State private var isPresentingFullScreenCover = false var body: some View { Button("Show FullScreenCover") { // 创建自定义事务,仅禁用系统默认的弹出动画 var transaction = Transaction() transaction.disablesAnimations = true withTransaction(transaction) { isPresentingFullScreenCover = true } } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.black) .fullScreenCover(isPresented: $isPresentingFullScreenCover) { FullScreenCoverView(isPresented: $isPresentingFullScreenCover) // 自定义弹出过渡动画 .transition(.scale.combined(with: .opacity)) .animation(.easeInOut(duration: 0.5), value: isPresentingFullScreenCover) } } } struct FullScreenCoverView: View { @Environment(\.dismiss) var dismiss @Binding var isPresented: Bool @State private var isDismissing = false var body: some View { Button("Dismiss") { // 先标记关闭状态,播放自定义动画 isDismissing = true // 延迟执行dismiss,等待自定义动画完成 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { var transaction = Transaction() transaction.disablesAnimations = true withTransaction(transaction) { isPresented = false } } } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.blue) // 自定义关闭动画:缩放+淡出 .opacity(isDismissing ? 0 : 1) .scaleEffect(isDismissing ? 0.5 : 1) .animation(.easeInOut(duration: 0.5), value: isDismissing) } }
方案说明:
- 弹出时:通过
Transaction局部禁用系统默认动画,同时给弹窗视图添加transition和animation,让自定义动画生效。 - 关闭时:先触发自定义退场动画,动画完成后再通过
Transaction禁用系统默认的关闭动画,修改绑定状态完成关闭。
内容的提问来源于stack exchange,提问作者José
相关产品推荐
相关产品推荐

