支持ObjC的Swift版 UILable文本数值变化效果

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 项目使用,经测试效果杠杠滴,具体效果参见下文图片:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追夢秋陽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值