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

如何让SwiftUI打字机动画更流畅、减少模糊效果?

SwiftUI打字机动画优化思路

当前你的打字机动画实现了基础的字符逐个显示效果,但现有代码里的withAnimation其实没有实际作用——因为字符串拼接更新animatedText时,Text控件的内容变化默认没有过渡动画,这个包裹不会产生任何视觉效果。下面是几个实用的优化方向,能大幅提升动画观感:

1. 给单个字符添加入场动画

把整段文本拆成单个字符的Text控件,给每个新出现的字符加上过渡动画,比如淡入+缩放效果:

struct TypewriterView: View {
    let text: String
    @State private var displayedChars: [Character] = []

    var body: some View {
        HStack(spacing: 0) {
            ForEach(displayedChars, id: \.self) { char in
                Text(String(char))
                    .transition(.opacity.combined(with: .scale))
            }
        }
        .font(.title)
        .padding()
        .onAppear {
            startTyping()
        }
    }

    private func startTyping() {
        for (index, char) in text.enumerated() {
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(index) * 0.05) {
                // 这里指定动画类型和时长,真正生效
                withAnimation(.easeInOut(duration: 0.1)) {
                    displayedChars.append(char)
                }
            }
        }
    }
}

2. 添加模拟打字光标

这是提升真实感的关键,给动画加上闪烁的光标,和打字进度联动:

HStack(spacing: 0) {
    // 已显示字符
    ForEach(displayedChars, id: \.self) { char in
        Text(String(char))
            .transition(.opacity.combined(with: .scale))
    }
    // 闪烁光标
    Text("|")
        .font(.title)
        // 打字时显示,完成后隐藏
        .opacity(displayedChars.count < text.count ? 1 : 0)
        // 永久闪烁动画
        .animation(.easeInOut(duration: 0.5).repeatForever(), value: displayedChars.count < text.count)
}

3. 优化打字节奏,贴近真实体验

  • 给字符添加随机小延迟,模拟人手打字的不规则速度:
let delay = Double(index) * 0.05 + Double.random(in: 0...0.02)
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
    // 添加字符逻辑
}
  • 给标点符号设置更长延迟,符合真实打字习惯:
let punctuation = [",", ".", "!", "?", ":", ";"]
let baseDelay = punctuation.contains(String(char)) ? 0.15 : 0.05
let delay = Double(index) * baseDelay + Double.random(in: 0...0.02)

4. 显式控制动画曲线

根据需求自定义动画类型:比如用.easeIn让字符弹出更有力度,.spring()增加弹性效果,或者调整时长让动画更柔和:

withAnimation(.spring(response: 0.1, dampingFraction: 0.8)) {
    displayedChars.append(char)
}

5. 支持重置和重复播放

添加重置功能,让动画可以重新触发:

@State private var isTyping = false

// 在body中添加按钮
Button("重新播放") {
    displayedChars.removeAll()
    startTyping()
}
.padding()

// 修改启动方法避免重复触发
private func startTyping() {
    guard !isTyping else { return }
    isTyping = true
    for (index, char) in text.enumerated() {
        let delay = Double(index) * 0.05 + Double.random(in: 0...0.02)
        DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
            withAnimation(.easeInOut(duration: 0.1)) {
                displayedChars.append(char)
            }
            if index == text.count - 1 {
                isTyping = false
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 08:25:27