カウントした数値を画面に出す機能を作っている際、数値が0からカウントアップして今の数値になるアニメーションを実装したい場面に遭遇しました。
このような一定時間内に任意の間隔で処理を実行する場面はそこそこあるかと思ったので以下のクラスを作成しました。
CountTimer.swift
class CountTimer {
private var timer: Timer?
private let interval: Double
private let execute_time: Double
private var current_time: Double = 0.0
init(count: Double, interval: Double, closure: @escaping (Double) -> Void) {
self.execute_time = count
self.interval = interval
self.timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(CountTimer.timerUpdate), userInfo: closure, repeats: true)
}
@objc private func timerUpdate(_ timer: Timer!) {
let closure = timer.userInfo as! (Double) -> Void
if current_time < execute_time {
self.current_time += self.interval
let percentage = floor(current_time / execute_time * 100) / 100
closure(percentage)
} else {
self.invalidate()
}
}
private func invalidate() {
self.timer?.invalidate()
}
}
実行する時間と実行間隔、処理内容のクロージャを渡し、一定の間隔で実行します。クロージャには全体の実行時間に対する現在のパーセンテージが小数点第二位までのDouble型で返すようにしてあります。
以下のように自分は使っています。
ViewController.swift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
_ = CountTimer(count: 3.0, interval: 0.1) { percentage -> Void in
print(percentage)
}
}
}
実行結果は以下のような感じです。全体3秒の処理を0.1秒間隔で実行しているため、一回につき0.03ずつ(1/30)増えていって、最後に1になっているのが確認できます。
冒頭で書いたLabelへのアニメーションは以下のような感じで使っています。値を受け取ったら3秒かけて0.05秒ごとに数値をカウントアップする処理が書けました。
ViewController.swift
class ViewController: UIViewController {
@IBOutlet weak var countLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
...
viewModel?.stepCount.observeNext { (value: Double) -> Void in
_ = StepTimer(count: 3.0, interval: 0.05) { percentage -> Void in
let count = value * percentage
self.countLabel.text = String(count)
}
}
}
}