zoukankan      html  css  js  c++  java
  • iOS

    1、数字动态变化

    • 具体实现代码见 GitHub 源码 QExtension

    • QCountingLabel.h

      	/// 文本数字变化方式枚举
      	typedef NS_ENUM(NSUInteger, QCountingMethod) {
      	    
      	    QCountingMethodEaseInOut,     // 开始结束慢,中间快
      	    QCountingMethodEaseIn,        // 开始慢,结束快
      	    QCountingMethodEaseOut,       // 开始快,结束慢
      	    QCountingMethodLinear         // 匀速
      	};
      	
      	@interface QCountingLabel : UILabel
      	
      	/// 文本数字样式,默认为 @"%f"
      	@property (nonatomic, strong) NSString *format;
      	
      	/// 文本数字分隔符样式,例如 @"###,##0.00"
      	@property (nonatomic, strong) NSString *positiveFormat;
      	
      	/// 文本数字变化方式,默认为 EaseInOut
      	@property (nonatomic, assign) QCountingMethod method;
      	
      	/// 文本数字变化时间,默认为 2.0
      	@property (nonatomic, assign) NSTimeInterval animationDuration;
      	
      	/// 文本数字样式 Block
      	@property (nonatomic, copy) NSString *(^formatBlock)(CGFloat);
      	
      	/// 富文本数字样式 Block
      	@property (nonatomic, copy) NSAttributedString *(^attributedFormatBlock)(CGFloat);
      	
      	/// 文本数字变化完成回调 Block
      	@property (nonatomic, copy) void (^completionBlock)();
      	
      	/**
      	 *  文本数字在指定时间内从起始值变化到结束值
      	 *
      	 *  @param frame            控件的 frame
      	 *  @param format           文本数字样式,默认为 @"%f"
      	 *  @param positiveFormat   文本数字分隔符样式
      	 *  @param method           文本数字变化方式,默认为 EaseInOut
      	 *  @param startValue       起始值
      	 *  @param endValue         结束值
      	 *  @param duration         变化时间
      	 *  @param completion       完成回调
      	 *
      	 *  @return QCountingLabel 对象
      	 */
      	+ (instancetype)q_countingLabelWithFrame:(CGRect)frame
      	                                  format:(NSString *)format
      	                          positiveFormat:(nullable NSString *)positiveFormat
      	                                  method:(QCountingMethod)method
      	                               fromValue:(CGFloat)startValue
      	                                 toValue:(CGFloat)endValue
      	                            withDuration:(NSTimeInterval)duration
      	                              completion:(void (^)())completion;
      	
      	/**
      	 *  文本数字从起始值变化到结束值
      	 *
      	 *  <p> 默认变化时间 2.0 秒 <p>
      	 *
      	 *  @param startValue   起始值
      	 *  @param endValue     结束值
      	 *
      	 *  @return nil
      	 */
      	- (void)q_countFromValue:(CGFloat)startValue toValue:(CGFloat)endValue;
      	
      	/**
      	 *  文本数字在指定时间内从起始值变化到结束值
      	 *
      	 *  @param startValue   起始值
      	 *  @param endValue     结束值
      	 *  @param duration     变化时间
      	 *
      	 *  @return nil
      	 */
      	- (void)q_countFromValue:(CGFloat)startValue toValue:(CGFloat)endValue withDuration:(NSTimeInterval)duration;
      	
      	/**
      	 *  文本数字从当前值变化到结束值
      	 *
      	 *  <p> 默认变化时间 2.0 秒 <p>
      	 *
      	 *  @param endValue     结束值
      	 *
      	 *  @return nil
      	 */
      	- (void)q_countFromCurrentValueToValue:(CGFloat)endValue;
      	
      	/**
      	 *  文本数字在指定时间内从当前值变化到结束值
      	 *
      	 *  @param endValue     结束值
      	 *  @param duration     变化时间
      	 *
      	 *  @return nil
      	 */
      	- (void)q_countFromCurrentValueToValue:(CGFloat)endValue withDuration:(NSTimeInterval)duration;
      	
      	/**
      	 *  文本数字从 0 变化到结束值
      	 *
      	 *  <p> 默认变化时间 2.0 秒 <p>
      	 *
      	 *  @param endValue     结束值
      	 *
      	 *  @return nil
      	 */
      	- (void)q_countFromZeroToValue:(CGFloat)endValue;
      	
      	/**
      	 *  文本数字在指定时间内从 0 变化到结束值
      	 *
      	 *  @param endValue     结束值
      	 *  @param duration     变化时间
      	 *
      	 *  @return nil
      	 */
      	- (void)q_countFromZeroToValue:(CGFloat)endValue withDuration:(NSTimeInterval)duration;
      	
      	@end
      
    • QCountingLabel.m

      	#ifndef kQLabelCounterRate
      	#define kQLabelCounterRate 3.0
      	#endif
      	
      	NS_ASSUME_NONNULL_BEGIN
      	
      	
      	@interface QCountingLabel ()
      	
      	@property (nonatomic, assign) CGFloat startingValue;
      	@property (nonatomic, assign) CGFloat destinationValue;
      	@property (nonatomic, assign) NSTimeInterval progress;
      	@property (nonatomic, assign) NSTimeInterval lastUpdate;
      	@property (nonatomic, assign) NSTimeInterval totalTime;
      	@property (nonatomic, assign) CGFloat easingRate;
      	
      	@property (nonatomic, strong, nullable) CADisplayLink *timer;
      	
      	@end
      	
      	@implementation QCountingLabel
      	
      	#pragma mark - 文本数字变化方法
      	
      	/// 创建 QCountingLabel 对象
      	+ (instancetype)q_countingLabelWithFrame:(CGRect)frame
      	                                  format:(NSString *)format
      	                          positiveFormat:(nullable NSString *)positiveFormat
      	                                  method:(QCountingMethod)method
      	                               fromValue:(CGFloat)startValue
      	                                 toValue:(CGFloat)endValue
      	                            withDuration:(NSTimeInterval)duration
      	                              completion:(void (^)())completion {
      	    
      	    QCountingLabel *label = [[self alloc] initWithFrame:frame];
      	    
      	    label.format = format;
      	    label.positiveFormat = positiveFormat;
      	    label.method = method;
      	    label.completionBlock = completion;
      	    [label q_countFromValue:startValue toValue:endValue withDuration:duration];
      	    
      	    return label;
      	}
      	
      	/// 文本数字从起始值变化到结束值
      	- (void)q_countFromValue:(CGFloat)startValue toValue:(CGFloat)endValue {
      	    
      	    if (self.animationDuration == 0.0f) {
      	        self.animationDuration = 2.0f;
      	    }
      	    
      	    [self q_countFromValue:startValue toValue:endValue withDuration:self.animationDuration];
      	}
      	
      	/// 文本数字在指定时间内从起始值变化到结束值
      	- (void)q_countFromValue:(CGFloat)startValue toValue:(CGFloat)endValue withDuration:(NSTimeInterval)duration {
      	    
      	    self.startingValue = startValue;
      	    self.destinationValue = endValue;
      	    
      	    // remove any (possible) old timers
      	    [self.timer invalidate];
      	    self.timer = nil;
      	    
      	    if (duration == 0.0) {
      	        
      	        // No animation
      	        [self q_setTextValue:endValue];
      	        
      	        if (self.completionBlock) {
      	            self.completionBlock();
      	        }
      	        
      	        return;
      	    }
      	    
      	    self.easingRate = 3.0f;
      	    self.progress = 0;
      	    self.totalTime = duration;
      	    self.lastUpdate = [NSDate timeIntervalSinceReferenceDate];
      	    
      	    if (self.format == nil) {
      	        self.format = @"%f";
      	    }
      	    
      	    CADisplayLink *timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(q_timerUpdate:)];
      	    timer.frameInterval = 2;
      	    [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
      	    [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode];
      	    self.timer = timer;
      	}
      	
      	/// 文本数字从当前值变化到结束值
      	- (void)q_countFromCurrentValueToValue:(CGFloat)endValue {
      	    
      	    [self q_countFromValue:[self q_getCurrentValue] toValue:endValue];
      	}
      	
      	/// 文本数字在指定时间内从当前值变化到结束值
      	- (void)q_countFromCurrentValueToValue:(CGFloat)endValue withDuration:(NSTimeInterval)duration {
      	    
      	    [self q_countFromValue:[self q_getCurrentValue] toValue:endValue withDuration:duration];
      	}
      	
      	/// 文本数字从 0 变化到结束值
      	- (void)q_countFromZeroToValue:(CGFloat)endValue {
      	    
      	    [self q_countFromValue:0.0f toValue:endValue];
      	}
      	
      	/// 文本数字在指定时间内从 0 变化到结束值
      	- (void)q_countFromZeroToValue:(CGFloat)endValue withDuration:(NSTimeInterval)duration {
      	    
      	    [self q_countFromValue:0.0f toValue:endValue withDuration:duration];
      	}
      	
      	/// format setter
      	- (void)setFormat:(NSString *)format {
      	    
      	    _format = format;
      	    
      	    // update label with new format
      	    [self q_setTextValue:self.q_getCurrentValue];
      	}
      	
      	#pragma mark - 工具方法
      	
      	/// 定时器定时响应事件处理
      	- (void)q_timerUpdate:(NSTimer *)timer {
      	    
      	    // update progress
      	    NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
      	    self.progress += now - self.lastUpdate;
      	    self.lastUpdate = now;
      	    
      	    if (self.progress >= self.totalTime) {
      	        [self.timer invalidate];
      	        self.timer = nil;
      	        self.progress = self.totalTime;
      	    }
      	    
      	    [self q_setTextValue:[self q_getCurrentValue]];
      	    
      	    if (self.progress == self.totalTime) {
      	        if (self.completionBlock) {
      	            self.completionBlock();
      	        }
      	    }
      	}
      	
      	/// 设置数值
      	- (void)q_setTextValue:(CGFloat)value {
      	    
      	    if (self.attributedFormatBlock != nil) {
      	        
      	        self.attributedText = self.attributedFormatBlock(value);
      	        
      	    } else if (self.formatBlock != nil) {
      	        
      	        self.text = self.formatBlock(value);
      	        
      	    } else {
      	        
      	        // check if counting with ints - cast to int
      	        if ([self.format rangeOfString:@"%(.*)d" options:NSRegularExpressionSearch].location != NSNotFound ||
      	            [self.format rangeOfString:@"%(.*)i"].location != NSNotFound) {
      	            
      	            // 整型样式
      	            self.text = [NSString stringWithFormat:self.format, (int)value];
      	            
      	        } else if (self.positiveFormat.length > 0) {
      	            
      	            // 带千分位分隔符的浮点型样式
      	            NSString *str = [NSString stringWithFormat:self.format, value];
      	            
      	            NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
      	            formatter.numberStyle = NSNumberFormatterDecimalStyle;
      	            [formatter setPositiveFormat:self.positiveFormat];
      	            NSString *formatterString = [formatter stringFromNumber:[NSNumber numberWithFloat:[str floatValue]]];
      	            
      	            self.text = formatterString;
      	            
      	        } else {
      	            
      	            // 普通浮点型样式
      	            self.text = [NSString stringWithFormat:self.format, value];
      	        }
      	    }
      	}
      	
      	/// 获取当前值
      	- (CGFloat)q_getCurrentValue {
      	    
      	    if (self.progress >= self.totalTime) {
      	        return self.destinationValue;
      	    }
      	    
      	    CGFloat percent = self.progress / self.totalTime;
      	    CGFloat updateVal = [self update:percent];
      	    
      	    return self.startingValue + (updateVal * (self.destinationValue - self.startingValue));
      	}
      	
      	/// 更新数值
      	- (CGFloat)update:(CGFloat)t {
      	    
      	    switch (self.method) {
      	            
      	        case 0: {
      	            int sign = 1;
      	            int r = (int)kQLabelCounterRate;
      	            
      	            if (r % 2 == 0) {
      	                sign = -1;
      	            }
      	            
      	            t *= 2;
      	            
      	            if (t < 1) {
      	                return 0.5f * powf(t, kQLabelCounterRate);
      	            } else {
      	                return sign * 0.5f * (powf(t - 2, kQLabelCounterRate) + sign * 2);
      	            }
      	            
      	            break;
      	        }
      	            
      	        case 1: {
      	            return powf(t, kQLabelCounterRate);
      	            
      	            break;
      	        }
      	            
      	        case 2: {
      	            return 1.0 - powf((1.0 - t), kQLabelCounterRate);
      	            
      	            break;
      	        }
      	            
      	        case 3: {
      	            return t;
      	            
      	            break;
      	        }
      	            
      	        default:
      	            return t;
      	    }
      	}
      	
      	@end
      
    • 使用

      • 1、初始化

        • QCountingLabel 继承自 UILabel, 初始化和 UILabel 一样

          	// 创建 QCountingLabel 对象
          	QCountingLabel *countingLabel = [[QCountingLabel alloc] initWithFrame:CGRectMake(0, 0, 300, 120)];
          	[self.view addSubview:countingLabel];
          	    
          	// 常规设置,QCountingLabel 继承 UILabel, 设置和 UILabel 一样
          	countingLabel.center = self.view.center;
          	countingLabel.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.5];
          	countingLabel.font = [UIFont systemFontOfSize:50];
          	countingLabel.textColor = [UIColor redColor];
          	countingLabel.textAlignment = NSTextAlignmentCenter;
          
        • 也可以使用类方法一体式创建设置

          	// 创建 QCountingLabel 对象
          	QCountingLabel *countingLabel = [QCountingLabel q_countingLabelWithFrame:CGRectMake(50, 100, 300, 120)
          	                                                                  format:@"%f"
          	                                                          positiveFormat:@"###,###.##"
          	                                                                  method:QCountingMethodEaseOut
          	                                                               fromValue:20
          	                                                                 toValue:3048.64
          	                                                            withDuration:10.0f
          	                                                              completion:^{
          	    
          	    NSLog(@"completion");
          	}];
          	    
          	[self.view addSubview:countingLabel];
          
      • 2、设置文本样式

        • 不设置时默认为 @"%f"

          	// 设置文本样式
          	countingLabel.format = @"%d";
          
        • 也可以使用 block 设置普通样式或富文本样式

          	// 设置文本样式,使用 block 可以根据不同的值设置多种不同的样式
          	countingLabel.formatBlock = ^NSString *(CGFloat value) {
          	    
          	    NSInteger years = value / 12;
          	    NSInteger months = (NSInteger)value % 12;
          	    
          	    if (years == 0) {
          	        
          	        return [NSString stringWithFormat: @"%ld 个月", (long)months];
          	        
          	    } else {
          	        
          	        return [NSString stringWithFormat: @"%ld 年, %ld 个月", (long)years, (long)months];
          	    }
          	};
          
      • 3、设置文本分隔符样式

        • 设置金额等金融数字时可以奢姿带有千分位分隔符的浮点数样式

          	// 设置分隔符样式
          	countingLabel.positiveFormat = @"###,###.##";
          
      • 4、设置文本变化方式

        • 不设置时默认为 EaseInOut

          	// 设置文本变化方式
          	countingLabel.method = QCountingMethodLinear;
          
      • 5、设置变化范围及动画时间

        • 不设置时间时默认为 2 秒

          	[countingLabel q_countFromValue:10 toValue:100];
          	
          	[countingLabel q_countFromValue:10 toValue:100 withDuration:1.0f];
          
      • 6、设置变化完成时的回调

        • 数字变化完成时,可以设置回调,再执行其他的操作

          	// 设置变化完成时的回调
          	countingLabel.completionBlock = ^void () {
          	    
          	    NSLog(@"completion");
          	};
          

    1.1 整数样式数字的变化

    • 创建设置代码

      	@property (nonatomic, strong) QCountingLabel *countingLabel;
      	
      	// 创建 QCountingLabel 对象
      	self.countingLabel = [[QCountingLabel alloc] initWithFrame:CGRectMake(0, 0, 300, 120)];
      	[self.view addSubview:self.countingLabel];
      	    
      	// 常规设置,QCountingLabel 继承 UILabel, 设置和 UILabel 一样
      	self.countingLabel.center = self.view.center;
      	self.countingLabel.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.5];
      	self.countingLabel.font = [UIFont systemFontOfSize:50];
      	self.countingLabel.textColor = [UIColor redColor];
      	self.countingLabel.textAlignment = NSTextAlignmentCenter;
      	    
      	// 设置文本样式
      	self.countingLabel.format = @"%d";
      	    
      	// 设置变化范围及动画时间
      	[self.countingLabel q_countFromValue:10 toValue:1000 withDuration:1.0f];
      
      • 效果

        Label3

    1.2 浮点数样式数字的变化

    • 创建设置代码

      	@property (nonatomic, strong) QCountingLabel *countingLabel;
      	
      	// 创建 QCountingLabel 对象
      	self.countingLabel = [[QCountingLabel alloc] initWithFrame:CGRectMake(0, 0, 300, 120)];
      	[self.view addSubview:self.countingLabel];
      	    
      	// 常规设置,QCountingLabel 继承 UILabel, 设置和 UILabel 一样
      	self.countingLabel.center = self.view.center;
      	self.countingLabel.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.5];
      	self.countingLabel.font = [UIFont systemFontOfSize:50];
      	self.countingLabel.textColor = [UIColor redColor];
      	self.countingLabel.textAlignment = NSTextAlignmentCenter;
      	    
      	// 设置文本样式
      	self.countingLabel.format = @"%.2f";
      	    
      	// 设置变化范围及动画时间
      	[self.countingLabel q_countFromValue:0 toValue:3198.23 withDuration:1.0f];
      
      • 效果

        Label4

    1.3 带有千分位分隔符的浮点数

    • 创建设置代码

      	@property (nonatomic, strong) QCountingLabel *countingLabel;
      	
      	// 创建 QCountingLabel 对象
      	self.countingLabel = [[QCountingLabel alloc] initWithFrame:CGRectMake(0, 0, 300, 120)];
      	[self.view addSubview:self.countingLabel];
      	    
      	// 常规设置,QCountingLabel 继承 UILabel, 设置和 UILabel 一样
      	self.countingLabel.center = self.view.center;
      	self.countingLabel.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.5];
      	self.countingLabel.font = [UIFont systemFontOfSize:50];
      	self.countingLabel.textColor = [UIColor redColor];
      	self.countingLabel.textAlignment = NSTextAlignmentCenter;
      	    
      	// 设置文本样式
      	self.countingLabel.format = @"%.2f";
      
      	// 设置分隔符样式
      	self.countingLabel.positiveFormat = @"###,###.##";
      	
      	// 设置变化范围及动画时间
      	[self.countingLabel q_countFromValue:0 toValue:3048.64 withDuration:1.0f];
      
      • 效果

        Label5

  • 相关阅读:
    Google Chrome中的高性能网络 (三)
    Linux入门基础 #5:Linux文件系统挂载管理
    git学习 #2:git基本操作
    ural 1018 Binary Apple Tree(树形dp | 经典)
    MST最小生成树及Prim普鲁姆算法
    UVA 10465 Homer Simpson(dp + 完全背包)
    Android 微信SDK分享功能中的最全过程步骤分析
    python第三方库推荐
    C. Tourist Problem
    Shell脚本编程——了解你的Linux系统必须掌握的20个命令
  • 原文地址:https://www.cnblogs.com/QianChia/p/6336431.html
Copyright © 2011-2022 走看看