Posted at

表示される値がアニメーションしながら変わるUILabelを作ってみた


はじめに

アプリを作っていると

UILabelで表示される値がぱっと切り替わると機械的だなー

と感じる箇所がちょいちょい出てきました。

なめらかに変わったら見るの楽しくなるなー、変わってる感もわかりやすいなー

と、ふと思ったので、作ってみることにしました。


結果

変化方法等、諸々はご自由に変化していただくとして()


実装

まず実装を見せますぜ。


final class AnimateValueLabel: UILabel {

private var loop : CADisplayLink?
private var startTime : TimeInterval = 0.0
private var currentValue : Int = 0
private var newValue : Int = 0

func setData(value: Int, animated: Bool = false) {
self.newValue = value
if animated && self.currentValue != self.newValue {
self.animateValue()
}
else {
self.currentValue = value
self.setText(value: self.currentValue)
}
}

private func animateValue() {
self.startTime = Date.timeIntervalSinceReferenceDate
self.loop = CADisplayLink(target: self, selector: #selector(self.update))

if #available(iOS 10.0, *) {
self.loop?.preferredFramesPerSecond = 60
}
else {
self.loop?.frameInterval = 1
}

self.loop?.add(to: .current, forMode: .common)
self.loop?.isPaused = false
}

@objc
private func update(displayLink: CADisplayLink) {
let duration : TimeInterval = 0.3
let elapsed : TimeInterval = Date.timeIntervalSinceReferenceDate - self.startTime

let progress: Int = Int(Easing.easeIn.quart.getProgress(elapsed: elapsed, duration: duration, startValue: CGFloat(self.currentValue), endValue: CGFloat(self.newValue)))

self.setText(value: progress)

if duration < elapsed {
self.loop?.isPaused = true
self.loop?.invalidate()
self.currentValue = self.newValue
}
}

private func setText(value: Int) {
self.text = value
}
}

CADisplayLinkやEasingに関しては過去記事を参考にしていただくとして、

https://qiita.com/haguhoms/items/c87d335756042bc867c4

https://qiita.com/haguhoms/items/abc5635e8fa95719cb12

これで、setDataに渡したvalueを、アニメーションしながら表示することに成功しました。

(コンマがついているのは、ここに書いたコードにはない機能です←)


最後に

もちろん、機械的が悪いとかそういう話では一切ありません。

し、全てがアニメーションすることが正しいわけでもないと思います。

が、抱いた不満や思いついたことを試してみて、体験価値的に良さげだったらプロダクトに導入する、そんな試みをひたすらやる旅も悪くないなって、つまりはそういうことです。