所謂「跑馬燈(Marquee)」就是一段文字從右到左跑過顯示器的效果,經常會在銀行、醫院、車站等公眾場所看到,對於有限的顯示空間(例如LED顯示器)特別好用。
本課就模擬火車站月台上看到的「南下列車將於1分鐘後進站」當做範例,用SwiftUI寫一個跑馬燈的程式。程式碼如下:
// 4-1a 跑馬燈 Text Animation
// Created by Heman, 2022/02/27
import PlaygroundSupport
import SwiftUI
var 訊息 = "南下列車即將於1分鐘後進站"
struct 跑馬燈: View {
@State var 位移: CGFloat = 450
let 動畫效果 = Animation.linear(duration: 10.0)
var body: some View {
Text(訊息)
.foregroundColor(.purple)
.font(.system(size: 36))
.frame(width: 800.0)
.lineLimit(1)
.offset(x: 位移, y: 0)
.onAppear {
withAnimation(動畫效果.repeatForever(autoreverses: false)) {
位移 = -450
}
}
}
}
PlaygroundPage.current.setLiveView(跑馬燈())
這段文字「南下列車即將於1分鐘後進站」之所以能動起來,主要就是利用SwiftUI的「Animation物件」,使用方法分為兩個步驟。
第一,先定義一個Animation物件實例:
let 動畫效果 = Animation.linear(duration: 10.0)
Animation 是物件類型(Type),有多種類型方法(Type method)可用來產出物件實例,這幾種方法分別對應不同的時間曲線,我們採用的 linear(duration: 10.0) 是線性變化,設定變化時間是10秒。
SwiftUI Animation 物件支援的時間曲線可參考下圖,包括線性 linear、緩入 easeIn、緩出 easeOut、緩入緩出 easeInOut、彈簧 spring、可自行定義時間曲線 timingCurve...等等。只有linear是定速,變化最平均,其他非線性的時間曲線,速度都會有所變化,產生更豐富的動畫效果。
圖片來源:https://www.objc.io/blog/2019/09/26/swiftui-animation-timing-curves/
第二步驟是在視圖一出現時(.onAppear),呼叫 withAnimation() 啟用動畫效果,withAnimation() 是一個「全域函式」(global function),意思是函式的有效範圍最大,在程式任何地方均可呼叫,同時也表示 withAnimation() 不屬於任何物件,這在SwiftUI物件庫中是比較少見的。
withAnimation() 需要一個Animation物件實例當作參數,之後再套一層「匿名函式」:
.onAppear {
withAnimation(動畫效果.repeatForever(autoreverses: false)) {
位移 = -450
}
}
這裡參數就用剛定義出來的Animation物件實例「動畫效果」,每個Animation物件實例都帶有若干實例方法(Instance method),可用來調整動畫行為,用法與視圖修飾語(View modifier)類似。Animation的實例方法包括:
其中repeatCount()與repeatForever()還可再加一個參數 autoreverses,表示要不要「倒轉」,預設是要倒轉(autoreverses: true)。如果4-1a範例程式用了預設倒轉,文字就會變成左右來回跑,而不是單向從右到左的跑馬燈,所以要加上(autoreverses: false)參數。
在後面跟隨的匿名函式中,我們將狀態變數(@State var)「位移」從原本的 450(單位是畫素「點」)改為-450,這個改變會觸發視圖的狀態變化,從而啟動動畫效果,關鍵的幾行程式碼如下:
@State var 位移: CGFloat = 450
let 動畫效果 = Animation.linear(duration: 10.0)
Text(訊息)
.offset(x: 位移, y: 0)
.onAppear {
withAnimation(動畫效果.repeatForever(autoreverses: false)) {
位移 = -450
}
}