I’m working on a counter app in SwiftUI where I have implemented a rolling text animation for the numbers. The animation works fine when the number is incremented one at a time. However, when the user rapidly increases the number by multiple inputs in quick succession, the animation freezes momentarily before resuming.
Here’s the code for my RollingText view:
//
// RollingText.swift
//
import SwiftUI
struct RollingText: View {
var font: Font = .largeTitle
var weight: Font.Weight = .regular
@Binding var value: Int
@State var animationRange: [Int] = []
@State var isAnimating = false
var body: some View {
HStack(spacing: 0) {
ForEach(0..<animationRange.count, id: \.self) { index in
Text("8")
.font(font)
.fontWeight(weight)
.opacity(0)
.overlay {
GeometryReader { proxy in
let size = proxy.size
VStack(spacing: 0) {
ForEach(0...9, id: \.self) { number in
Text("\(number)")
.font(font)
.fontWeight(weight)
.frame(width: size.width, height: size.height, alignment: .center)
}
}
.offset(y: -CGFloat(animationRange[index]) * size.height)
}
.clipped()
}
}
}
.onAppear {
animationRange = Array(repeating: 0, count: "\(value)".count)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.06) {
updateText()
}
}
.onChange(of: value) { newValue in
// 새 값에 따라 animationRange의 길이를 조정합니다.
adjustAnimationRange(for: newValue)
// 진행 중인 애니메이션에 대한 목표 값을 업데이트합니다.
if isAnimating {
for (index, value) in zip(0..<"\(newValue)".count, "\(newValue)") {
animationRange[index] = (String(value) as NSString).integerValue
}
} else {
updateText()
}
}
}
func adjustAnimationRange(for newValue: Int) {
let newCount = "\(newValue)".count
let extra = newCount - animationRange.count
if extra > 0 {
animationRange += Array(repeating: 0, count: extra)
} else if extra < 0 {
animationRange.removeLast(-extra)
}
}
func updateText() {
isAnimating = true
let stringValue = "\(value)"
var longestAnimationDuration = 0.0
for (index, value) in zip(0..<stringValue.count, stringValue) {
let fraction = min(Double(index) * 0.15, 0.5)
let animationDuration = 0.8 + fraction // 이 값은 애니메이션의 실제 시간에 따라 조정해야 합니다.
withAnimation(.interactiveSpring(response: 0.8, dampingFraction: 1 + fraction, blendDuration: 1 + fraction)) {
animationRange[index] = (String(value) as NSString).integerValue
}
if animationDuration > longestAnimationDuration {
longestAnimationDuration = animationDuration
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + longestAnimationDuration) {
isAnimating = false
}
}
}
struct RollingText_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The issue seems to arise when there’s fast, repeated user interaction. The animation gets stuck for a short period and then continues. I’m looking for a way to make the animation smooth and continuous, even with rapid user inputs.
How can I modify my SwiftUI code to handle rapid changes in the counter value without interrupting the rolling animation effect?




