[英]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.