新建一个Swift工程。要做到数字滚动的动画,可能很多人都会想到用UIView的animate方法,但是UIView的animate方法只会做关于UIView的Frame,alpha,color,transform的相关操作,所以这里用UIView的animate是无法做到这些效果的。这里需要需要用到——CADisplaylink,一个允许你的应用根据屏幕刷新率同步进行应用的绘制工作的计时器对象。
先创建一个Label。
let countingLabel: UILabel = {
let label = UILabel()
label.text = "1234"
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 18)
return label
}()
将其加入到subview里面并且赋予其frame。
view.addSubview(countingLabel)
countingLabel.frame = view.frame
然后创建一个CADisplayLink,并将其加入到主线程runloop里面。
let displayLink = CADisplayLink(target: self, selector: #selector(handleUpdate))
displayLink.add(to: .main, forMode: .default)
创建开始值和结束值
var startValue = 0.0
let endValue = 1200.0
在之前的displayLink响应方法里面写入一下代码后运行可以看到Label里面的数字在跳动啦。
@objc func handleUpdate() {
self.countingLabel.text = "\(startValue)"
startValue += 1
if startValue > endValue {
startValue = endValue
}
}
获取当前时间,并且设置好想要的时长
let animationDuration = 1.5
let animationStartDate = Date()
然后修改handleUpdate方法,将其根据过去的时间以及设定好的动画时长来改变UILabel的数值。
@objc func handleUpdate() {
let now = Date()
let elapsedTime = now.timeIntervalSince(animationStartDate)
if elapsedTime > animationDuration {
self.countingLabel.text = "\(endValue)"
} else {
let percentage = elapsedTime / animationDuration
let value = startValue + percentage * (endValue - startValue)
self.countingLabel.text = "\(value)"
}
}
这里还有两个问题,一个就是displayLink的移除,一个是数值后面的小数点。
要displayLink的移除这个问题就要把displayLink移到外面作为VC的一个属性,然后在动画结束后移除。而要解决小数点问题则把值转为Int就可以了。
最终代码:
import UIKit
class ViewController: UIViewController {
let countingLabel: UILabel = {
let label = UILabel()
label.text = "1234"
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 18)
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(countingLabel)
countingLabel.frame = view.frame
displayLink = CADisplayLink(target: self, selector: #selector(handleUpdate))
displayLink?.add(to: .main, forMode: .default)
}
var startValue = 0.0
let endValue = 1200.0
var displayLink: CADisplayLink?
let animationDuration = 1.5
let animationStartDate = Date()
@objc func handleUpdate() {
let now = Date()
let elapsedTime = now.timeIntervalSince(animationStartDate)
if elapsedTime > animationDuration {
self.countingLabel.text = "\(Int(endValue))"
displayLink?.invalidate()
displayLink = nil
} else {
let percentage = elapsedTime / animationDuration
let value = startValue + percentage * (endValue - startValue)
self.countingLabel.text = "\(Int(value))"
}
}
}