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

  • 相关阅读:
    poj 1743 Musical Theme 后缀数组
    poj 1743 Musical Theme 后缀数组
    cf 432D Prefixes and Suffixes kmp
    cf 432D Prefixes and Suffixes kmp
    hdu Data Structure? 线段树
    关于position和anchorPoint之间的关系
    ios POST 信息
    CALayers的代码示例
    CALayers详解
    ios中得sqlite使用基础
  • 原文地址:https://www.cnblogs.com/QianChia/p/6336431.html
Copyright © 2011-2022 走看看