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

如何禁用SwiftUI中CircularProgressViewStyle样式ProgressView的动画?

解决SwiftUI CircularProgressView动画禁用问题(快照测试专用)

你试过的方法无效,主要是因为CircularProgressView的内置动画(比如无限旋转、进度变化动画)不受普通的animation(nil)或transaction控制,这些动画是组件内部独立驱动的。下面给你几个可靠的方案:

方案1:自定义无动画的圆形进度样式(iOS 15+)

直接实现一个完全静态的ProgressViewStyle,完全绕开系统的动画逻辑:

struct StaticCircularProgressStyle: ProgressViewStyle {
    func makeBody(configuration: Configuration) -> some View {
        let progress = configuration.fractionCompleted ?? 0.0
        
        return Circle()
            .stroke(Color.secondary.opacity(0.3), lineWidth: 4)
            .overlay(
                Circle()
                    .trim(from: 0, to: progress)
                    .stroke(Color.accentColor, lineWidth: 4)
                    .rotationEffect(.degrees(-90))
            )
            .frame(width: 24, height: 24)
    }
}

// 使用示例
// 无限加载状态(无进度值)
ProgressView()
    .progressViewStyle(StaticCircularProgressStyle())

// 带进度值的状态
ProgressView(value: 60, total: 100)
    .progressViewStyle(StaticCircularProgressStyle())

这个样式完全是静态绘制的,没有任何动画,完美适配快照测试。

方案2:用UIKit组件包装(兼容iOS 13+)

如果需要支持更早系统版本,直接用UIKit的组件来替代,手动禁用动画:

针对无限加载的静态指示器:

struct StaticActivityIndicator: UIViewRepresentable {
    func makeUIView(context: Context) -> UIActivityIndicatorView {
        let indicator = UIActivityIndicatorView(style: .medium)
        indicator.stopAnimating() // 直接停止动画,显示静态轮廓
        return indicator
    }
    
    func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {}
}

// 使用
StaticActivityIndicator()

针对带进度值的静态圆形进度:

struct StaticCircularProgress: UIViewRepresentable {
    let progress: Double
    
    func makeUIView(context: Context) -> UIProgressView {
        let progressView = UIProgressView(progressViewStyle: .circular)
        progressView.progress = Float(progress)
        // UIKit的圆形进度默认无动画,直接赋值即可
        return progressView
    }
    
    func updateUIView(_ uiView: UIProgressView, context: Context) {
        uiView.progress = Float(progress)
    }
}

// 使用
StaticCircularProgress(progress: 0.5)

方案3:快照测试时的全局动画屏蔽(仅部分场景有效)

如果不想修改视图代码,可以在快照测试代码里给目标视图添加双重动画屏蔽,但注意这个方法对系统CircularProgressView的无限旋转动画可能无效:

let testView = ProgressView()
    .progressViewStyle(CircularProgressViewStyle())
    .environment(\.animation, nil)
    .transaction { $0.animation = nil }

// 执行快照拍摄

为什么你之前的方法没用?

  • .disabled(true):只禁用交互,不影响动画播放;
  • .animation(nill):拼写错误(应该是nil),而且仅控制视图状态变化时的环境动画,管不了组件内部的循环动画;
  • .transaction { ... }:同样只影响状态变更动画,对系统内置的循环旋转动画无效。

内容的提问来源于stack exchange,提问作者Oliver Pearmain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:03:30