SwiftUI -动画计数文本从0到x

mgdq6dx1  于 2023-11-16  发布在  Swift
关注(0)|答案(4)|浏览(127)

我想动画一个文本,默认情况下从0开始,到一个变量。
例如,对于x = 80,我希望我的文本能够非常快地显示0到80之间的所有数字,直到它达到80。
你有什么想法吗?
谢谢戴克拉西斯

um6iljoc

um6iljoc1#

在这里,我创建了一个名为runCounter的小函数,它接受一个绑定到counter变量、一个start值、end值和speed。当调用时,它将绑定变量设置为start值,然后启动Timer,该Timerspeed秒运行一次,并递增计数器,直到它达到end,在该点它使timer无效。
这个独立的示例显示了两个以不同速度运行的计数器,这两个计数器都在使用.onAppear()首次出现时启动。

struct ContentView: View {
    @State private var counter1 = 0
    @State private var counter2 = 0
    
    var body: some View {
        VStack {
        Text("\(self.counter1)")
            .onAppear {
                self.runCounter(counter: self.$counter1, start: 0, end: 80, speed: 0.05)
            }
        Text("\(self.counter2)")
            .onAppear {
                self.runCounter(counter: self.$counter2, start: 0, end: 10, speed: 0.5)
            }
        }
    }
    
    func runCounter(counter: Binding<Int>, start: Int, end: Int, speed: Double) {
        counter.wrappedValue = start

        Timer.scheduledTimer(withTimeInterval: speed, repeats: true) { timer in
            counter.wrappedValue += 1
            if counter.wrappedValue == end {
                timer.invalidate()
            }
        }
    }
}

字符串

a11xaf1n

a11xaf1n2#

您可以使用Timer.Publisher定期触发计数器的递增。
要在达到所需计数后停止递增,每当Timer触发时,您可以检查count是否已达到end,如果没有,则递增它,否则删除订阅并停止递增。

class Counter: ObservableObject {
    @Published var count = 0
    let end: Int

    private var timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
    private var subscriptions = Set<AnyCancellable>()

    init(end: Int) {
        self.end = end
    }

    func start() {
        timer.sink { [weak self] _ in
            guard let self = self else { return }
            if self.count <=self.end {
                self.count += 1
            } else {
                self.subscriptions.removeAll()
            }
        }.store(in: &subscriptions)
    }
}

struct AnimatedText: View {
    @ObservedObject var counter: Counter

    var body: some View {
        Text("\(counter.count)")
            .onAppear() {
                self.counter.start()
            }
    }
}

struct AnimatedText_Previews: PreviewProvider {
    static var previews: some View {
        AnimatedText(counter: Counter(end: 80))
    }
}

字符串

ruyhziif

ruyhziif3#

添加到@vacawama的答案。

func runCounter(counter: Binding<Int>, start: Int, end: Int, speed: Double) {
    let maxSteps = 20
    counter.wrappedValue = start
    
    let steps = min(abs(end), maxSteps)
    var increment = 1
    if steps == maxSteps {increment = end/maxSteps}

    Timer.scheduledTimer(withTimeInterval: speed, repeats: true) { timer in
        counter.wrappedValue += increment
        if counter.wrappedValue >= end {
            counter.wrappedValue = end
            timer.invalidate()
        }
    }
}

字符串

wbgh16ku

wbgh16ku4#

这里有一个利用SwiftUI内置动画功能的解决方案。因此,它不需要管理任何计时器或动画循环本身。
它也不局限于从0移动到最终数字。在withAnimation块中执行的value的任何更改都将通过移动中间值来动画值的更改。

import SwiftUI

struct AnimatedNumberTextView<Content>: View, Animatable where Content: View {
    private var value: Double
    @ViewBuilder private let content: (Int) -> Content
    
    init(_ value: Int, content: @escaping (Int) -> Content) {
        self.value = Double(value)
        self.content = content
    }
    
    var animatableData: Double {
        get { value }
        set { value = newValue }
    }
    
    var body: some View {
        content(Int(value))
    }
}

struct ContentView: View {
    @State private var number = 0
    
    var body: some View {
        HStack {
            Text("Riches:")

            AnimatedNumberTextView(number) { value in
                Text("\(value) 😮")
                    .monospaced()
            }.frame(minWidth: 140, alignment: .trailing)
        }
        .padding(.bottom)
        .onAppear {
            withAnimation(.easeInOut(duration: 2)) {
                number = 87654321
            }
        }
        
        Button("Randomise!") {
            withAnimation(.easeInOut(duration: 1)) {
                number = Int.random(in: 0...87654321)
            }
        }
    }
}

字符串
(灵感来自this blogthis blog

相关问题