我想动画一个文本,默认情况下从0开始,到一个变量。例如,对于x = 80,我希望我的文本能够非常快地显示0到80之间的所有数字,直到它达到80。你有什么想法吗?谢谢戴克拉西斯
um6iljoc1#
在这里,我创建了一个名为runCounter的小函数,它接受一个绑定到counter变量、一个start值、end值和speed。当调用时,它将绑定变量设置为start值,然后启动Timer,该Timer每speed秒运行一次,并递增计数器,直到它达到end,在该点它使timer无效。这个独立的示例显示了两个以不同速度运行的计数器,这两个计数器都在使用.onAppear()首次出现时启动。
runCounter
counter
start
end
speed
Timer
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() } } } }
字符串
a11xaf1n2#
您可以使用Timer.Publisher定期触发计数器的递增。要在达到所需计数后停止递增,每当Timer触发时,您可以检查count是否已达到end,如果没有,则递增它,否则删除订阅并停止递增。
Timer.Publisher
count
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)) } }
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() } } }
wbgh16ku4#
这里有一个利用SwiftUI内置动画功能的解决方案。因此,它不需要管理任何计时器或动画循环本身。它也不局限于从0移动到最终数字。在withAnimation块中执行的value的任何更改都将通过移动中间值来动画值的更改。
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 blog和this blog。
4条答案
按热度按时间um6iljoc1#
在这里,我创建了一个名为
runCounter
的小函数,它接受一个绑定到counter
变量、一个start
值、end
值和speed
。当调用时,它将绑定变量设置为start
值,然后启动Timer
,该Timer
每speed
秒运行一次,并递增计数器,直到它达到end
,在该点它使timer
无效。这个独立的示例显示了两个以不同速度运行的计数器,这两个计数器都在使用
.onAppear()
首次出现时启动。字符串
a11xaf1n2#
您可以使用
Timer.Publisher
定期触发计数器的递增。要在达到所需计数后停止递增,每当
Timer
触发时,您可以检查count
是否已达到end
,如果没有,则递增它,否则删除订阅并停止递增。字符串
ruyhziif3#
添加到@vacawama的答案。
字符串
wbgh16ku4#
这里有一个利用SwiftUI内置动画功能的解决方案。因此,它不需要管理任何计时器或动画循环本身。
它也不局限于从
0
移动到最终数字。在withAnimation
块中执行的value
的任何更改都将通过移动中间值来动画值的更改。字符串
(灵感来自this blog和this blog。