[英]SwiftUI animate text component when value changes
假设我有一个显示两个数字的 SwiftUI 组件。 下面的示例代码模拟了一个简单的情况,即随机不时更新两个数字。
struct ContentView: View {
@State var number1: Int = 0
@State var number2: Int = 0
var timer:Timer {
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
if (Int.random(in: 0...100)<10) {
print("random event happened, increase numbers!")
self.number1 = self.number1 + 1
self.number2 = self.number2 + 1
}
}
}
var body: some View {
ZStack {
SampleNumbersView(numbers1: number1, numbers2: number2)
}.onAppear {
let _ = self.timer
}
}
}
struct SampleNumbersView: View {
var numbers1:Int = 0
var numbers2:Int = 0
var body: some View {
VStack {
Text("Number 1: \(numbers1)")
Text("Number 2: \(numbers2)")
}
}
}
上面的代码有效。 但是,如果我希望在更新两个数字时发生以下动画序列,该怎么办?
理论上动画的功能大致是这样的
func updateNumber1and2(number1: Int, number2:Int) {
//first show number1
self.number1 = number1
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { _ in
//next show number 2
self.number2 = number2
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { _ in
//next blink text twice
print("start blinking")
self.numbersBlinking = true
Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { _ in
print("stop blinking")
self.numbersBlinking = false
}
}
}
}
但是我不知道何时或如何在 SwiftUI 组件中执行这样的函数?
SwiftUI 有一个内置的动画函数,它们是由变量的变化触发的。 你不必自己滚动。 当然不是多个计时器。 如果您要使用计时器,则可以使用一个计时器,并根据该计时器跟踪事情何时发生变化。 不建议使用多个定时器。
由于您列出的要求,此代码比普通动画稍微复杂一些,但您需要延迟。 如果您只是希望视图在更改时闪烁,我会简单地将animator
包装在withAnimation()
块中,它会在更改时立即闪烁。
struct AnimatedTextView: View {
@State var number1: Int = 0
@State var number2: Int = 0
@State var animator = false
var body: some View {
VStack {
Button { // Changed your timer to a button so that you don't have to wait for some random event
self.number1 = self.number1 + 1
// This delays the execution by 1 second.
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.number2 = self.number2 + 1
}
// This delays the execution by 2 seconds.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation(.easeInOut(duration: 0.2).repeatCount(10)) {
// Changing this to true causes the opacity of the view to go to 0.
// By putting it in an animated block, the change will be slowed and repeated 5 times
// On and off each separately count as a time
animator = true
}
// This delays the execution by 1 second after the animator variable is changed.
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// This gives time for the animation to complete and then sets the opacity back to 1
// Otherwise the view will be hidden. It is essentially a reset.
animator = false
}
}
} label: {
Text("Change Numbers")
}
SampleNumbersView(numbers1: number1, numbers2: number2)
// animator is used here to change the opacity, and it is animated repeatedly
// causing the view to blink.
.opacity(animator ? 0 : 1)
}
}
}
struct SampleNumbersView: View {
// Since you are not changing the numbers in this view, declare them as let
// and do not give them an initial value. There is less system overhead.
let numbers1: Int
let numbers2: Int
var body: some View {
VStack {
Text("Number 1: \(numbers1)")
Text("Number 2: \(numbers2)")
}
}
}
而且,为了回答您的原始问题,如果您使用的是 iOS 14 或更高版本,您将在其中一个视图上使用.onChange(of:perform:)
来捕获更新并像这样运行您的函数:
.onChange(of: number1) { _ in
updateNumber1and2(number1: number1, number2:number2)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.