目的とするアニメーション
別のクラスを作成するため、比較的キレイにコードが書けると思います。
CountAnimateLabel.swift
import UIKit
final class CountAnimateLabel: UILabel{
var startTime: CFTimeInterval!
var fromValue: Int!
var toValue: Int!
var duration: TimeInterval!
func animate(from fromValue: Int, to toValue: Int, duration: TimeInterval) {
text = "\(fromValue)"
// 開始時間を保存
self.startTime = CACurrentMediaTime()
self.fromValue = fromValue
self.toValue = toValue
self.duration = duration
// CADisplayLinkの生成
let link = CADisplayLink(target: self, selector: #selector(updateValue))
link.add(to: .current, forMode: .default)
}
// 描画タイミング毎に呼ばれるメソッド
@objc func updateValue(link: CADisplayLink) {
// 開始からの進捗 0.0 〜 1.0くらい
let dt = (link.timestamp - self.startTime) / duration
// 終了時に最後の値を入れてCADisplayLinkを破棄
if dt >= 1.0 {
text = "\(toValue!)"
link.invalidate()
return
}
// 最初の値に進捗に応じた値を足して現在の値を計算
let current = Int(Double(toValue - fromValue) * dt) + fromValue
text = "\(current)"
}
}
このクラスをインスタンス化して、任意のタイミングでanimateメソッドを呼び出します。
CountAnimateLabel.swift
import UIKit
final class ShowSumViewController: UIViewController {
var label: CountAnimateLabel!
override func viewDidLoad() {
super.viewDidLoad()
setUpViews()
}
private func setUpViews() {
label = CountAnimateLabel()
let labelWidth = 200
let labelHeight = 100
label.frame = CGRect(x: (Int(view.frame.size.width) - labelWidth) / 2 , y: (Int(view.frame.size.height) - labelHeight) / 2, width: labelWidth, height: labelHeight)
label.textColor = .black
label.textAlignment = .center
label.font = label.font.withSize(100)
view.addSubview(label)
label.animate(from: 0, to: 100, duration: 0.7)
}
}
fromは開始時の数字、toは終了時の数字、durationは時間を表しているので、適宜変更してください。
参考
使わせていただきました 🐝