You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
    }
}

方案说明:

  1. 弹出时:通过Transaction局部禁用系统默认动画,同时给弹窗视图添加transition和animation,让自定义动画生效。
  2. 关闭时:先触发自定义退场动画,动画完成后再通过Transaction禁用系统默认的关闭动画,修改绑定状态完成关闭。

内容的提问来源于stack exchange,提问作者José

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 11:46:04