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

SwiftUI数值更新时如何实现文本组件的分步序列动画效果?

SwiftUI 分步数字更新加闪烁动画实现方案

你原来的实现问题在于触发更新时直接修改了两个数字的状态,会导致视图立刻同步刷新,无法实现分步展示的效果。你可以按以下方式修改代码:

核心实现思路

  • 触发更新时先计算目标值,不要直接修改视图绑定的状态变量
  • 用DispatchQueue.main.asyncAfter替代嵌套Timer实现时间序列控制,代码更简洁,也不用额外处理Timer的生命周期
  • 闪烁效果直接用SwiftUI内置的重复动画实现,不用手动控制每一次透明度切换

完整可运行代码

ContentView 实现

struct ContentView: View {
    @State private var number1: Int = 0
    @State private var number2: Int = 0
    @State private var isBlinking: Bool = false
    
    var timer: Timer {
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
            if Int.random(in: 0...100) < 10 {
                print("random event happened, increase numbers!")
                // 预计算目标更新值
                let targetNum1 = number1 + 1
                let targetNum2 = number2 + 1
                // 调用序列更新方法
                runUpdateSequence(num1: targetNum1, num2: targetNum2)
            }
        }
    }
    
    var body: some View {
        ZStack {
            SampleNumbersView(
                num1: number1,
                num2: number2,
                isBlinking: isBlinking
            )
        }.onAppear {
            let _ = timer
        }
    }
    
    private func runUpdateSequence(num1: Int, num2: Int) {
        // 第一步:立刻更新第一个数字
        number1 = num1
        
        // 1秒后更新第二个数字
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            number2 = num2
            
            // 再间隔1秒触发闪烁
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                print("start blinking")
                // 两次完整闪烁:每次闪烁包含显示/隐藏两个阶段,所以repeatCount设为4
                withAnimation(.easeInOut(duration: 0.2).repeatCount(4, autoreverses: true)) {
                    isBlinking = true
                }
                // 闪烁结束后重置状态
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
                    isBlinking = false
                    print("stop blinking")
                }
            }
        }
    }
}

SampleNumbersView 实现

struct SampleNumbersView: View {
    var num1: Int = 0
    var num2: Int = 0
    var isBlinking: Bool = false
    
    var body: some View {
        VStack(spacing: 16) {
            Text("Number 1: \(num1)")
                .opacity(isBlinking ? 0 : 1)
            Text("Number 2: \(num2)")
                .opacity(isBlinking ? 0 : 1)
        }
    }
}

自定义调整说明

  • 如果要修改数字更新的间隔,直接调整asyncAfter的deadline参数即可
  • 如果要修改闪烁次数,调整repeatCount的数值即可:每多一次完整闪烁增加2个计数(比如3次闪烁设为6)
  • 如果要修改闪烁速度,调整duration的参数即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 23:06:03