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

SwiftUI动画过程中获取当前值 实现环形进度条百分比文本同步动画

问题原因

SwiftUI 默认不对文本内容的变化做逐帧插值更新,直接绑定manager.progress的文本只会在属性值变更完成后刷新,无法跟随环形进度的动画过程同步更新。

解决方案

方案1:iOS 15+ 极简实现

直接给文本添加数字内容过渡动画即可,同时将动画和manager.progress绑定保证同步,修改后完整代码如下:

struct LoadingScreen: View {
    @ObservedObject var manager : OnboardingManager
    
    var body: some View {
        ZStack {
            Circle()
                .stroke(lineWidth: 20.0)
                .opacity(0.3)
                .foregroundColor(Color.red)
            
            Circle()
                .trim(from: 0.0, to: CGFloat(min(self.manager.progress, 1.0)))
                .stroke(style: StrokeStyle(lineWidth: 20.0, lineCap: .round, lineJoin: .round))
                .foregroundColor(Color.red)
                .rotationEffect(Angle(degrees: 270.0))
                // 动画绑定progress,避免多余隐式动画
                .animation(.linear(duration: manager.progressDuration), value: manager.progress)
            
            Text(String(format: "%.0f %%", min(self.manager.progress, 1.0)*100.0))
                .font(.largeTitle)
                .bold()
                // 数字内容过渡
                .contentTransition(.numericText())
                // 和圆环同步动画参数
                .animation(.linear(duration: manager.progressDuration), value: manager.progress)
                .onTapGesture(perform: {
                    // 用withAnimation包裹触发更新,保证全局动画同步
                    withAnimation(.linear(duration: manager.progressDuration)) {
                        manager.executeLoad()
                    }
                })
        }
    }
}

方案2:兼容iOS 15以下版本

通过自定义遵守AnimatableModifier协议的修饰器,实现逐帧插值渲染文本:

  1. 先定义可动画的百分比文本修饰器
struct AnimatablePercentText: AnimatableModifier {
    var progress: Double
    let decimalPlaces: Int = 0
    
    var animatableData: Double {
        get { progress }
        set { progress = newValue }
    }
    
    func body(content: Content) -> some View {
        Text(String(format: "%.\(decimalPlaces)f %%", min(progress, 1.0)*100))
            .font(.largeTitle)
            .bold()
    }
}

extension View {
    func animatablePercent(progress: Double) -> some View {
        self.modifier(AnimatablePercentText(progress: progress))
    }
}
  1. 替换原文本部分的代码即可
EmptyView()
    .animatablePercent(progress: manager.progress)
    .animation(.linear(duration: manager.progressDuration), value: manager.progress)
    .onTapGesture(perform: {
        withAnimation(.linear(duration: manager.progressDuration)) {
            manager.executeLoad()
        }
    })

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:24:06