AnimatingLabel.swift 一种UILable 文本数值变化效果,强大简单实用。具体文件参考如下:
import Foundation
import UIKit
public protocol TextContainable: class {
var text: String? { get set }
}
public protocol DigitAnimatable: TextContainable {
func animate(to value: Double, duration: Double, formatter: NumberFormatter?, easingOption: EasingOption)
}
public extension DigitAnimatable {
public func animate(to value: Double, duration: Double = 1, formatter: NumberFormatter? = nil, easingOption: EasingOption = .easeInOut) {
let numberFormatter: NumberFormatter
if let formatter = formatter {
numberFormatter = formatter
} else {
numberFormatter = NumberFormatter()
numberFormatter.minimumFractionDigits = 2
}
let text: String = self.text ?? (numberFormatter.string(for: 0) ?? "0")
let number = numberFormatter.number(from: text)?.doubleValue ?? 0
let diff = value - number
CustomAnimator(duration: duration, easingOption: easingOption, update: { [weak self] progress in
self?.text = numberFormatter.string(for: number + diff * progress)
}, completion: {
self.text = numberFormatter.string(for: value)
})
}
}
extension UILabel: DigitAnimatable {}
//MARK: - Implementation
open class CustomAnimator: NSObject {
private var timer: CADisplayLink?
open private(set) var lastUpdate: TimeInterval
open private(set) var progress: TimeInterval = 0
open private(set) var duration: TimeInterval
open var update: ((Double) -> Void)
open var completion: (() -> Void)?
open private(set) var easingOption: EasingOption
@discardableResult
public init(duration: TimeInterval, easingOption: EasingOption = .easeInOut, update: @escaping (Double) -> Void, completion: (() -> Void)? = nil) {
self.lastUpdate = Date.timeIntervalSinceReferenceDate
self.duration = duration
self.update = update
self.easingOption = easingOption
self.completion = completion
super.init()
self.timer = CADisplayLink(target: self, selector: #selector(CustomAnimator.tick(timer:)))
if #available(iOS 10.0, *) {
self.timer?.preferredFramesPerSecond = 60
} else {
self.timer?.frameInterval = 1
}
self.timer?.add(to: .current, forMode: .common)
self.timer?.add(to: .current, forMode: .tracking)
self.update(0)
}
@objc(tick:) open func tick(timer: Timer) {
let now = Date.timeIntervalSinceReferenceDate
self.progress += now - self.lastUpdate
self.lastUpdate = now
if self.progress > self.duration {
self.timer?.invalidate()
self.update(1)
self.timer = nil
self.completion?()
return
}
self.update(self.easingOption.ease(self.progress / self.duration))
}
/**
* 数字动画(供ObjC 调用)
* @param toValue Double 最终显示的值
* @param duration Double 动画时间
*/
@objc(animationLable:toValue:andDuration:) open func animationLable(labInfo:UILabel,toValue value:Double,andDuration duration:Double){
let labSwift:UILabel? = labInfo;
labSwift?.animate(to: value,
duration: duration,
formatter: nil,
easingOption: .easeInOut)
}
}
public enum EasingOption {
case linear
case easeIn
case easeOut
case easeInOut
}
public extension EasingOption {
public func ease(_ t: Double) -> Double {
switch self {
case .linear:
return t
case .easeIn:
return pow(t, 2)
case .easeOut:
return 1.0 - pow(1.0 - t, 2)
case .easeInOut:
let sign: Double = -1
let t = t * 2
if t < 1 {
return 0.5 * pow(t, 2)
} else {
return sign * 0.5 * (pow(t - 2, 2) + sign * 2)
}
}
}
}
Swift 项目中直接使用即可,在ObjC中引入 app名-Swift.h 文件 ,具体操作可参考网络文章,ObjC中 调用方法如下:
CustomAnimator *customAnimator = [CustomAnimator alloc];
self.labCurrentInfo.text = @"0.00";//一定要先清理下
[customAnimator animationLable:self.labCurrentInfo
toValue:5000.0 //最终值
andDuration:3]; //动画时间,单位秒
补充:原文作者已不可考,版权归原作者所有,上文中 animationLable 方法是本人后来新增是为了能在ObjC 项目使用,经测试效果杠杠滴,具体效果参见下文图片: