Commit 7491a21a cgx

今日积分添加动画(该动画用户体验需要优化)

1 个父辈 f0390d7d
正在显示 61 个修改的文件 包含 1183 行增加168 行删除
......@@ -34,6 +34,7 @@
D01C9D6E28168BFC00163567 /* WSDatePickerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D01C9D6B28168BFC00163567 /* WSDatePickerView.xib */; };
D01C9D6F28168BFC00163567 /* WSDatePickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = D01C9D6C28168BFC00163567 /* WSDatePickerView.m */; };
D01C9D7028168BFC00163567 /* NSDate+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = D01C9D6D28168BFC00163567 /* NSDate+Extension.m */; };
D01D3CCD2873DD6B00E65BAA /* DPScrollNumberLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = D01D3CCB2873DD6B00E65BAA /* DPScrollNumberLabel.m */; };
D01DC95128701ECD0035B78B /* MyPointView.m in Sources */ = {isa = PBXBuildFile; fileRef = D01DC95028701ECD0035B78B /* MyPointView.m */; };
D01DC954287022740035B78B /* ScoreLevelView.m in Sources */ = {isa = PBXBuildFile; fileRef = D01DC953287022740035B78B /* ScoreLevelView.m */; };
D01DC957287023C20035B78B /* RankHeadView.m in Sources */ = {isa = PBXBuildFile; fileRef = D01DC956287023C20035B78B /* RankHeadView.m */; };
......@@ -302,6 +303,8 @@
D01C9D6B28168BFC00163567 /* WSDatePickerView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WSDatePickerView.xib; sourceTree = "<group>"; };
D01C9D6C28168BFC00163567 /* WSDatePickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WSDatePickerView.m; sourceTree = "<group>"; };
D01C9D6D28168BFC00163567 /* NSDate+Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+Extension.m"; sourceTree = "<group>"; };
D01D3CCB2873DD6B00E65BAA /* DPScrollNumberLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DPScrollNumberLabel.m; sourceTree = "<group>"; };
D01D3CCC2873DD6B00E65BAA /* DPScrollNumberLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DPScrollNumberLabel.h; sourceTree = "<group>"; };
D01DC94F28701ECD0035B78B /* MyPointView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyPointView.h; sourceTree = "<group>"; };
D01DC95028701ECD0035B78B /* MyPointView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyPointView.m; sourceTree = "<group>"; };
D01DC952287022740035B78B /* ScoreLevelView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScoreLevelView.h; sourceTree = "<group>"; };
......@@ -840,6 +843,104 @@
path = WSDaePickerView;
sourceTree = "<group>";
};
D01D3CCA2873DD6B00E65BAA /* DPScrollNumberLabel */ = {
isa = PBXGroup;
children = (
D01D3CCB2873DD6B00E65BAA /* DPScrollNumberLabel.m */,
D01D3CCC2873DD6B00E65BAA /* DPScrollNumberLabel.h */,
);
path = DPScrollNumberLabel;
sourceTree = "<group>";
};
D01D3CCE2873EC7D00E65BAA /* Controller */ = {
isa = PBXGroup;
children = (
D0D4107A2844B8DB00009638 /* DailyTaskController.h */,
D0D4107B2844B8DB00009638 /* DailyTaskController.m */,
D091E666283F0E8800D3279E /* MyPointController.h */,
D091E667283F0E8800D3279E /* MyPointController.m */,
D091E66C283F29D100D3279E /* ScoreDetailController.h */,
D091E66D283F29D100D3279E /* ScoreDetailController.m */,
D091E66F283F2E6F00D3279E /* ScoreDetailListController.h */,
D091E670283F2E6F00D3279E /* ScoreDetailListController.m */,
);
path = Controller;
sourceTree = "<group>";
};
D01D3CCF2873ECCA00E65BAA /* RequestModel */ = {
isa = PBXGroup;
children = (
D091E663283F0C4800D3279E /* ScoreTaskRequestModel.h */,
D091E664283F0C4800D3279E /* ScoreTaskRequestModel.m */,
);
path = RequestModel;
sourceTree = "<group>";
};
D01D3CD02873ECE000E65BAA /* Model */ = {
isa = PBXGroup;
children = (
D0BE536C2845A7AF007F15B3 /* SignModel.h */,
D0BE536D2845A7AF007F15B3 /* SignModel.m */,
D0D4107D2844D38400009638 /* RankModel.h */,
D0D4107E2844D38400009638 /* RankModel.m */,
D0BE536F2845AFD8007F15B3 /* NewTaskModel.h */,
D0BE53702845AFD8007F15B3 /* NewTaskModel.m */,
D0BE53722845B27E007F15B3 /* DailyTaskModel.h */,
D0BE53732845B27E007F15B3 /* DailyTaskModel.m */,
D091E669283F120100D3279E /* MyScoreModel.h */,
D091E66A283F120100D3279E /* MyScoreModel.m */,
D0D5BB0B286D7A8D00D0507E /* TaskGroupModel.h */,
D0D5BB0C286D7A8D00D0507E /* TaskGroupModel.m */,
D091E672283F5B4200D3279E /* ScoreDetailModel.h */,
D091E673283F5B4200D3279E /* ScoreDetailModel.m */,
);
path = Model;
sourceTree = "<group>";
};
D01D3CD12873ED1500E65BAA /* View */ = {
isa = PBXGroup;
children = (
D0336161285035AB005573CF /* DailyBgView.h */,
D0336162285035AB005573CF /* DailyBgView.m */,
D037C495284F4A22000F3089 /* SignTaskView.h */,
D037C496284F4A22000F3089 /* SignTaskView.m */,
D037C498284F4F0D000F3089 /* DailyTaskCell.h */,
D037C499284F4F0D000F3089 /* DailyTaskCell.m */,
D07257F1286BF99F0080F458 /* DailyTaskView.h */,
D07257F2286BF99F0080F458 /* DailyTaskView.m */,
D07257F4286C2F110080F458 /* SignCollectionViewCell.h */,
D07257F5286C2F110080F458 /* SignCollectionViewCell.m */,
D037C49B284F5DE8000F3089 /* TaskPointSrollView.h */,
D037C49C284F5DE8000F3089 /* TaskPointSrollView.m */,
D0404A292870930A0062AD30 /* BeizerView.h */,
D0404A2A2870930A0062AD30 /* BeizerView.m */,
D01DC95828702F260035B78B /* RankViewCell.h */,
D01DC95928702F260035B78B /* RankViewCell.m */,
D01DC94F28701ECD0035B78B /* MyPointView.h */,
D01DC95028701ECD0035B78B /* MyPointView.m */,
D01DC955287023C20035B78B /* RankHeadView.h */,
D01DC956287023C20035B78B /* RankHeadView.m */,
D01DC952287022740035B78B /* ScoreLevelView.h */,
D01DC953287022740035B78B /* ScoreLevelView.m */,
D0071C6E28707BCB0035AD8A /* ScoreRulesView.h */,
D0071C6F28707BCC0035AD8A /* ScoreRulesView.m */,
D091E675283F614900D3279E /* ScoreDetailCell.h */,
D091E676283F614900D3279E /* ScoreDetailCell.m */,
);
path = View;
sourceTree = "<group>";
};
D01D3CD22873ED5900E65BAA /* Tool */ = {
isa = PBXGroup;
children = (
D049886C286E9209000ACF55 /* TaskTimerTool.h */,
D049886D286E9209000ACF55 /* TaskTimerTool.m */,
D0498872286E95F2000ACF55 /* DsTaskManager.h */,
D0498873286E95F2000ACF55 /* DsTaskManager.m */,
);
path = Tool;
sourceTree = "<group>";
};
D027EE2327FB3C99004BBA61 /* Network */ = {
isa = PBXGroup;
children = (
......@@ -1101,60 +1202,11 @@
D091E662283F0BD400D3279E /* ScoreTaskAI */ = {
isa = PBXGroup;
children = (
D091E663283F0C4800D3279E /* ScoreTaskRequestModel.h */,
D091E664283F0C4800D3279E /* ScoreTaskRequestModel.m */,
D091E666283F0E8800D3279E /* MyPointController.h */,
D091E667283F0E8800D3279E /* MyPointController.m */,
D01DC94F28701ECD0035B78B /* MyPointView.h */,
D01DC95028701ECD0035B78B /* MyPointView.m */,
D01DC952287022740035B78B /* ScoreLevelView.h */,
D01DC953287022740035B78B /* ScoreLevelView.m */,
D0404A292870930A0062AD30 /* BeizerView.h */,
D0404A2A2870930A0062AD30 /* BeizerView.m */,
D0071C6E28707BCB0035AD8A /* ScoreRulesView.h */,
D0071C6F28707BCC0035AD8A /* ScoreRulesView.m */,
D01DC955287023C20035B78B /* RankHeadView.h */,
D01DC956287023C20035B78B /* RankHeadView.m */,
D01DC95828702F260035B78B /* RankViewCell.h */,
D01DC95928702F260035B78B /* RankViewCell.m */,
D091E669283F120100D3279E /* MyScoreModel.h */,
D091E66A283F120100D3279E /* MyScoreModel.m */,
D091E672283F5B4200D3279E /* ScoreDetailModel.h */,
D091E673283F5B4200D3279E /* ScoreDetailModel.m */,
D091E675283F614900D3279E /* ScoreDetailCell.h */,
D091E676283F614900D3279E /* ScoreDetailCell.m */,
D091E66C283F29D100D3279E /* ScoreDetailController.h */,
D091E66D283F29D100D3279E /* ScoreDetailController.m */,
D091E66F283F2E6F00D3279E /* ScoreDetailListController.h */,
D091E670283F2E6F00D3279E /* ScoreDetailListController.m */,
D037C495284F4A22000F3089 /* SignTaskView.h */,
D037C496284F4A22000F3089 /* SignTaskView.m */,
D07257F4286C2F110080F458 /* SignCollectionViewCell.h */,
D07257F5286C2F110080F458 /* SignCollectionViewCell.m */,
D037C498284F4F0D000F3089 /* DailyTaskCell.h */,
D037C499284F4F0D000F3089 /* DailyTaskCell.m */,
D07257F1286BF99F0080F458 /* DailyTaskView.h */,
D07257F2286BF99F0080F458 /* DailyTaskView.m */,
D0D5BB0B286D7A8D00D0507E /* TaskGroupModel.h */,
D0D5BB0C286D7A8D00D0507E /* TaskGroupModel.m */,
D0D4107A2844B8DB00009638 /* DailyTaskController.h */,
D0D4107B2844B8DB00009638 /* DailyTaskController.m */,
D0336161285035AB005573CF /* DailyBgView.h */,
D0336162285035AB005573CF /* DailyBgView.m */,
D037C49B284F5DE8000F3089 /* TaskPointSrollView.h */,
D037C49C284F5DE8000F3089 /* TaskPointSrollView.m */,
D0D4107D2844D38400009638 /* RankModel.h */,
D0D4107E2844D38400009638 /* RankModel.m */,
D0BE536C2845A7AF007F15B3 /* SignModel.h */,
D0BE536D2845A7AF007F15B3 /* SignModel.m */,
D0BE53722845B27E007F15B3 /* DailyTaskModel.h */,
D0BE53732845B27E007F15B3 /* DailyTaskModel.m */,
D0BE536F2845AFD8007F15B3 /* NewTaskModel.h */,
D0BE53702845AFD8007F15B3 /* NewTaskModel.m */,
D049886C286E9209000ACF55 /* TaskTimerTool.h */,
D049886D286E9209000ACF55 /* TaskTimerTool.m */,
D0498872286E95F2000ACF55 /* DsTaskManager.h */,
D0498873286E95F2000ACF55 /* DsTaskManager.m */,
D01D3CD22873ED5900E65BAA /* Tool */,
D01D3CD12873ED1500E65BAA /* View */,
D01D3CD02873ECE000E65BAA /* Model */,
D01D3CCE2873EC7D00E65BAA /* Controller */,
D01D3CCF2873ECCA00E65BAA /* RequestModel */,
);
path = ScoreTaskAI;
sourceTree = "<group>";
......@@ -1531,6 +1583,7 @@
D07DAC912810557D0067A1BF /* RSKImageCropper */,
D01C9D6828168BFC00163567 /* WSDaePickerView */,
D0E65FF32807A654006562F2 /* HYBUnicodeReadable */,
D01D3CCA2873DD6B00E65BAA /* DPScrollNumberLabel */,
D08F79B6281A1838000D99DD /* TZImagePickerController */,
D0878F49280BEFF9005F1B7F /* YBAttributeTextTapAction */,
);
......@@ -2009,6 +2062,7 @@
D07257F3286BF99F0080F458 /* DailyTaskView.m in Sources */,
D0534F092835D90400F8892E /* DSNaviBarViewController.m in Sources */,
D04B3D9A27F6D4D90022F8DF /* LeadingController.m in Sources */,
D01D3CCD2873DD6B00E65BAA /* DPScrollNumberLabel.m in Sources */,
D0031549284DAC0D00CFE94D /* RelaxBodyView.m in Sources */,
D0404A2B2870930A0062AD30 /* BeizerView.m in Sources */,
D053BEE9280F9E310028CCFC /* CloseAlertView.m in Sources */,
......
//
// BeizerView.m
// DreamSleep
//
// Created by peter on 2022/7/2.
//
#import "BeizerView.h"
@interface BeizerView ()
@property(nonatomic,assign) float step;
@property(nonatomic,assign) float total;
@end
@implementation BeizerView
- (void)drawRect:(CGRect)rect
{
[[UIColor orangeColor] set];
DSLog(@"====:%f, %f", self.width, self.height);
UIBezierPath *path9 = [UIBezierPath bezierPath];
[path9 moveToPoint:CGPointMake(0, self.height)];
[path9 addLineToPoint:CGPointMake(36+36, self.height)];
[path9 addCurveToPoint:CGPointMake(self.width, 0) controlPoint1:CGPointMake(36+36, self.height) controlPoint2:CGPointMake(self.width - 56, self.height - 34)];
// [path9 addQuadCurveToPoint:CGPointMake(self.width, 0) controlPoint:CGPointMake(self.width - 56, self.height - 34)];
// [path9 stroke];
// 创建CAShapeLayer
CAShapeLayer *layer = [CAShapeLayer layer];
layer.fillColor = [UIColor clearColor].CGColor;
layer.lineWidth = 2.0f;
layer.lineCap = kCALineCapRound;
layer.lineJoin = kCALineJoinRound;
layer.strokeColor = [UIColor blueColor].CGColor;
[self.layer addSublayer:layer];
layer.path = path9.CGPath;
// CAGradientLayer *gradLayer = [CAGradientLayer layer];
// gradLayer.frame = CGRectMake(100, 100, 100, 100);
// gradLayer.colors = @[(__bridge id)[UIColor redColor].CGColor,(__bridge id)[UIColor greenColor].CGColor,(__bridge id)[UIColor orangeColor].CGColor];
// gradLayer.startPoint = CGPointMake(0, 1);
// gradLayer.endPoint = CGPointMake(1, 1);
// gradLayer.locations = @[@0.2,@0.5,@0.7];
// gradLayer.type = kCAGradientLayerAxial;
// [layer addSublayer:gradLayer];
// 创建Animation
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.fromValue = @(0.0);
animation.toValue = @(1.0);
layer.autoreverses = NO;
animation.duration = 4.0;
// 设置layer的animation
[layer addAnimation:animation forKey:nil];
}
- (void)animateProgress:(float)progress animate:(BOOL)animate
{
// _progressRate = progress;
if (animate) {
self.total = progress;
/*
利用定时器做进度动画
*/
[NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(numberAnimation:)
userInfo:nil
repeats:YES];
}else{
[self setNeedsDisplay];
}
}
-(void)numberAnimation:(NSTimer*)timer {
_step += 0.01;
if (self.step > self.total) {
[timer invalidate];
timer = nil;
self.step = 0;
return;
}
self.progressRate = self.step;
[self setNeedsDisplay];
}
@end
//
// BeizerView.m
// DreamSleep
//
// Created by peter on 2022/7/2.
//
#import "BeizerView.h"
@interface BeizerView ()
@property(nonatomic,assign) float step;
@property(nonatomic,assign) float total;
@end
@implementation BeizerView
- (void)drawRect:(CGRect)rect
{
CGFloat x = -self.width, y = -self.height, width = 2*self.width, height = 2*self.height, startAngle = -95*M_PI_2/90.0, endAngle = -15*M_PI_2/90.0;
CGContextRef context = UIGraphicsGetCurrentContext();
//设置填充颜色
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
//画椭圆,这里画的是个实心椭圆
//如果想画椭圆的边框,只需要把这句改为
CGContextStrokeEllipseInRect(context, CGRectMake(x, y, width, height));
// CGContextFillEllipseInRect(context, CGRectMake(x, y, width, height));
CGContextSaveGState(context);
//
// CGPoint center = CGPointMake(x + width / 2.0, y + height / 2.0);
// UIBezierPath* clip = [UIBezierPath bezierPathWithArcCenter:center
// radius:MAX(width, height)
// startAngle:startAngle
// endAngle:endAngle
// clockwise:NO];
// [clip addLineToPoint:center];
// [clip closePath];
// [clip addClip];
//
// UIBezierPath *arc = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x, y, width, height)];
// [[UIColor blackColor] setStroke];
// [arc stroke];
CGContextRestoreGState(context);
// 绘制总弧线
// UIBezierPath *aPath1 = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-self.width, -self.height -2, 2*self.width + 2, 2*self.height + 2)];
// aPath1.lineWidth = 2;
// aPath1.lineJoinStyle = kCGLineJoinRound;
// [UIColor.blueColor set];
// [aPath1 stroke];
// [self debugViewShowBorder];
// 渐变色
// CAGradientLayer *gradLayer = [CAGradientLayer layer];
// gradLayer.frame = aPath1.bounds;
// gradLayer.colors = @[(__bridge id)ColorFromHex(0x9CE5EF).CGColor,(__bridge id)ColorFromHex(0x217B8B).CGColor];
// gradLayer.startPoint = CGPointMake(0, .5);
// gradLayer.endPoint = CGPointMake(1, .5);
// gradLayer.locations = @[@0,@1.0];
// gradLayer.type = kCAGradientLayerRadial;
// [self.layer addSublayer:gradLayer];
// 绘制当前弧线
// UIBezierPath *aPath2=[UIBezierPath bezierPathWithOvalInRect:CGRectMake(-self.width, -self.height -2, 2*self.width + 2, 2*self.height + 2)];
// aPath2.lineWidth = 2.0;
// [aPath2 stroke];
// self.clipsToBounds = YES;
// UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(50, 0)
// radius:self.width
// startAngle:-75*M_PI_2/90
// endAngle:-55*M_PI_2/90
// clockwise:NO];
// aPath.lineWidth = 2.0;
// aPath.lineCapStyle = kCGLineCapRound; //线条拐角
// aPath.lineJoinStyle = kCGLineJoinRound; //终点处理
// [aPath stroke];
// self.clipsToBounds = YES;
// [self debugViewShowBorder];
// 创建CAShapeLayer
// CAShapeLayer *layer = [CAShapeLayer layer];
// layer.fillColor = [UIColor clearColor].CGColor;
// layer.lineWidth = 2.0f;
// layer.lineCap = kCALineCapRound;
// layer.lineJoin = kCALineJoinRound;
// layer.strokeColor = [UIColor blueColor].CGColor;
// [self.layer addSublayer:layer];
// layer.path = aPath.CGPath;
// 创建Animation
// CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
// animation.fromValue = @(0.0);
// animation.toValue = @(1.0);
// layer.autoreverses = NO;
// animation.duration = 4.0;
// 设置layer的animation
// [layer addAnimation:animation forKey:nil];
}
- (void)animateProgress:(float)progress animate:(BOOL)animate
{
// _progressRate = progress;
if (animate) {
self.total = progress;
/*
利用定时器做进度动画
*/
[NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(numberAnimation:)
userInfo:nil
repeats:YES];
}else{
[self setNeedsDisplay];
}
}
-(void)numberAnimation:(NSTimer*)timer {
_step += 0.01;
if (self.step > self.total) {
[timer invalidate];
timer = nil;
self.step = 0;
return;
}
self.progressRate = self.step;
[self setNeedsDisplay];
}
@end
......@@ -6,10 +6,11 @@
//
#import "DailyBgView.h"
#import "DPScrollNumberLabel.h"
@interface DailyBgView ()
@property (nonatomic, strong) UIImageView *bgIV;
@property (nonatomic, strong) UILabel *pointsLab;
@property (nonatomic, strong) DPScrollNumberLabel *pointsLab;
@property (nonatomic, strong) UILabel *todayLab;
@end
......@@ -25,19 +26,18 @@
}
- (void)updateTodayPointData:(int)points {
self.pointsLab.text = [NSString stringWithFormat:@"%d", points];
// 积分需要动画显示效果
[self.pointsLab changeToNumber:@(points) animated:YES];
self.todayLab.text = @"今日积分";
[self.pointsLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self).offset(15);
make.top.equalTo(self).offset(136);
make.size.mas_equalTo(CGSizeMake(self.pointsLab.frame.size.width, self.pointsLab.frame.size.height));
}];
[self.todayLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.pointsLab.mas_right).offset(2);
make.bottom.equalTo(self.pointsLab).offset(-9);
}];
// 积分需要动画显示效果
}
#pragma mark - lazy
......@@ -49,10 +49,10 @@
return _bgIV;
}
- (UILabel *)pointsLab {
- (DPScrollNumberLabel *)pointsLab {
if (!_pointsLab) {
_pointsLab = [UILabel labWithFont:BoldFont(46.0)];
_pointsLab.dk_textColorPicker = DKColorPickerWithKey(Dk_TITLE);
_pointsLab = [[DPScrollNumberLabel alloc] initWithNumber:@(0) fontSize:46.0 signSetting:SignSettingUnsigned];
_pointsLab.minRowNumber = 1;
}
return _pointsLab;
}
......
......@@ -55,7 +55,7 @@
[self.beizerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.cardIV);
make.bottom.equalTo(self.cardIV).offset(-36);
make.height.equalTo(@76);
make.top.equalTo(self.cardIV).offset(38);
}];
}
return self;
......@@ -151,7 +151,7 @@
_beizerView = [[BeizerView alloc]initWithFrame:CGRectZero];
_beizerView.x = 50;
_beizerView.y = 50;
_beizerView.radius = 40;
// _beizerView.radius = 40;
_beizerView.backgroundColor = DSClearColor;
// [_beizerView debugViewShowBorder];
// _beizerView.layer.anchorPoint = CGPointMake(0.5, 0.5);
......
//
// DPScrollNumberLabel.h
// DPScrollNumberLabelDemo
//
// Created by Dai Pei on 16/5/23.
// Copyright © 2016年 Dai Pei. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
The setting option for SignSetting
- SignSettingUnsigned: only display positive number, default configuration is unsigned
- SignSettingNormal: negative numbers have negative sign but positive numbers don't have sign
- SignSettingSigned: positive numbers have sign as well as negative numbers
- default: SignSettingUnsigned
*/
typedef NS_ENUM(NSUInteger, SignSetting) {
SignSettingUnsigned,
SignSettingNormal,
SignSettingSigned
};
@interface DPScrollNumberLabel : UIView
/**
It synchronize with the value you set by method '-changeToNumber:animated:' and '-changeToNumber:interval:animated:'
*/
@property (nonatomic, strong, readonly)NSNumber *currentNumber;
/**
This property control the minimum display row.
if set this property to 2, and currentNumber is 1, the display is 01
*/
@property (nonatomic, assign)NSUInteger minRowNumber;
/**
Dynamic init method, the instance created by this method have a dynamic row count, it's row will change with the value you setting
@param number the initial number you want to display
@param fontSize the number font size you want
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize;
/**
Dynamic init method, the instance created by this method have a dynamic row count, it's row will change with the value you setting
@param number the initial number you want to display
@param fontSize the number font size you want
@param textColor the number color you want
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize textColor:(UIColor *)textColor;
/**
Dynamic init method, the instance created by this method have a dynamic row count, it's row will change with the value you setting
@param number the initial number you want to display
@param fontSize the number font size you want
@param signSetting the sign setting for DPScrollNumberLabel, you have three option: unsigned, normal, signed. see SignSetting enum declaration for detail.
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize signSetting:(SignSetting)signSetting;
/**
Dynamic init method, the instance created by this method have a dynamic row count, it's row will change with the value you setting
@param number the initial number you want to display
@param fontSize the number font size you want
@param textColor the number color you want
@param signSetting the sign setting for DPScrollNumberLabel, you have three option: unsigned, normal, signed. see SignSetting enum declaration for detail.
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize textColor:(UIColor *)textColor signSetting:(SignSetting)signSetting;
/**
Dynamic init method, the instance created by this method have a dynamic row count, it's row will change with the value you setting
@param number the initial number you want to display
@param font the number font you want
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font;
/**
Dynamic init method, the instance created by this method have a dynamic row count, it's row will change with the value you setting
@param number the initial number you want to display
@param font the number font you want
@param textColor the number color you want
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font textColor:(UIColor *)textColor;
/**
Dynamic init method, the instance created by this method have a dynamic row count, it's row will change with the value you setting
@param number the initial number you want to display
@param font the number font you want
@param signSetting the sign setting for DPScrollNumberLabel, you have three option: unsigned, normal, signed. see SignSetting enum declaration for detail.
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font signSetting:(SignSetting)signSetting;
/**
Dynamic init method, the instance created by this method have a dynamic row count, it's row will change with the value you setting
@param number the initial number you want to display
@param font the number font you want
@param textColor the number color you want
@param signSetting the sign setting for DPScrollNumberLabel, you have three option: unsigned, normal, signed. see SignSetting enum declaration for detail.
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font textColor:(UIColor *)textColor signSetting:(SignSetting)signSetting;
/*-------------------------------------------- Dynamic init method end -------------------------------------------------
If you set row number, the DPScrollNumberLabel instance's max num will less than the row num.
For example, you set row number to 1, then the max count of this label will be 9.
Note:rowNumber shouldn't more than 8
---------------------------------------------- Static init method start -----------------------------------------------*/
/**
Static init method, the instance created by this method have a comfirmed row count,
if your value's row bigger than the comfirmed row, it won't have effect
@param number the initial number you want to display
@param fontSize the number font size you want
@param rowNumber the row count of DPScrollNumberLabel, it means the row count will be changeless
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number
fontSize:(CGFloat)fontSize
rowNumber:(NSUInteger)rowNumber;
/**
Static init method, the instance created by this method have a comfirmed row count,
if your value's row bigger than the comfirmed row, it won't have effect
@param number the initial number you want to display
@param fontSize the number font size you want
@param textColor the number color you want
@param rowNumber the row count of DPScrollNumberLabel, it means the row count will be changeless
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number
fontSize:(CGFloat)fontSize
textColor:(UIColor *)textColor
rowNumber:(NSUInteger)rowNumber;
/**
Static init method, the instance created by this method have a comfirmed row count,
if your value's row bigger than the comfirmed row, it won't have effect
@param number the initial number you want to display
@param fontSize the number font size you want
@param signSetting the sign setting for DPScrollNumberLabel, you have three option: unsigned, normal, signed. see SignSetting enum declaration for detail.
@param rowNumber the row count of DPScrollNumberLabel, it means the row count will be changeless
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number
fontSize:(CGFloat)fontSize
signSetting:(SignSetting)signSetting
rowNumber:(NSUInteger)rowNumber;
/**
Static init method, the instance created by this method have a comfirmed row count,
if your value's row bigger than the comfirmed row, it won't have effect
@param number the initial number you want to display
@param fontSize the number font size you want
@param textColor the number color you want
@param signSetting the sign setting for DPScrollNumberLabel, you have three option: unsigned, normal, signed. see SignSetting enum declaration for detail.
@param rowNumber the row count of DPScrollNumberLabel, it means the row count will be changeless
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number
fontSize:(CGFloat)fontSize
textColor:(UIColor *)textColor
signSetting:(SignSetting)signSetting
rowNumber:(NSUInteger)rowNumber;
/**
Static init method, the instance created by this method have a comfirmed row count,
if your value's row bigger than the comfirmed row, it won't have effect
@param number the initial number you want to display
@param font the number font you want
@param textColor the number color you want
@param rowNumber the row count of DPScrollNumberLabel, it means the row count will be changeless
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number
font:(UIFont *)font
textColor:(UIColor *)textColor
rowNumber:(NSUInteger)rowNumber;
/**
Static init method, the instance created by this method have a comfirmed row count,
if your value's row bigger than the comfirmed row, it won't have effect
@param number the initial number you want to display
@param font the number font you want
@param signSetting the sign setting for DPScrollNumberLabel, you have three option: unsigned, normal, signed. see SignSetting enum declaration for detail.
@param rowNumber the row count of DPScrollNumberLabel, it means the row count will be changeless
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number
font:(UIFont *)font
signSetting:(SignSetting)signSetting
rowNumber:(NSUInteger)rowNumber;
/**
Static init method, the instance created by this method have a comfirmed row count,
if your value's row bigger than the comfirmed row, it won't have effect
@param number the initial number you want to display
@param font the number font you want
@param textColor the number color you want
@param signSetting the sign setting for DPScrollNumberLabel, you have three option: unsigned, normal, signed. see SignSetting enum declaration for detail.
@param rowNumber the row count of DPScrollNumberLabel, it means the row count will be changeless
@return the instance of DPScrollNumberLabel
*/
- (instancetype)initWithNumber:(NSNumber *)number
font:(UIFont *)font
textColor:(UIColor *)textColor
signSetting:(SignSetting)signSetting
rowNumber:(NSUInteger)rowNumber;
/**
When you want to change the display value, you can use this method,
and the interval of scroll animation will be calculated automatically
@param number the number you want to display
@param animated if you pass NO, the label will display your number without animation
*/
- (void)changeToNumber:(NSNumber *)number animated:(BOOL)animated;
/**
When you want to change the display value and you want to calculate
the animation interval by yourself, you should use this method
@param number the number you want to display
@param interval the animation interval
@param animated if you pass NO, the label will display your number withour animation
*/
- (void)changeToNumber:(NSNumber *)number interval:(CGFloat)interval animated:(BOOL)animated;
@end
//
// DPScrollNumberLabel.m
// DPScrollNumberLabelDemo
//
// Created by Dai Pei on 16/5/23.
// Copyright © 2016年 Dai Pei. All rights reserved.
//
#import "DPScrollNumberLabel.h"
@interface DPAnimationAttribute : NSObject
@property (nonatomic, assign) NSInteger repeatCount;
@property (nonatomic, assign) CGFloat startDuration;
@property (nonatomic, assign) CGFloat cycleDuration;
@property (nonatomic, assign) CGFloat endDuration;
@property (nonatomic, assign) NSInteger targetNumber;
@property (nonatomic, assign) CGFloat startDelay;
@property (nonatomic, assign) NSInteger sign;
@end
@implementation DPAnimationAttribute
@end
@interface DPAnimationTask : NSObject
@property (nonatomic, assign) NSInteger targetNumber;
@property (nonatomic, assign) NSInteger changeValue;
@property (nonatomic, assign) CGFloat interval;
@end
@implementation DPAnimationTask
@end
typedef NS_ENUM(NSUInteger, ScrollAnimationDirection) {
ScrollAnimationDirectionIncrease,
ScrollAnimationDirectionDecrease,
ScrollAnimationDirectionCount
};
typedef NS_ENUM(NSUInteger, Sign) {
SignNegative = 0,
SignZero = 1, // when the display number is zero, there is no sign
SignPositive = 2
};
static const CGFloat normalModulus = 0.3f;
static const CGFloat bufferModulus = 0.7f;
static const NSUInteger numberCellLineCount = 21;
static const NSUInteger signCellLineCount = 3;
static NSString * const numberCellText = @"0\n9\n8\n7\n6\n5\n4\n3\n2\n1\n0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n0";
@interface DPScrollNumberLabel()
@property (nonatomic, strong, readwrite) NSNumber *currentNumber;
@property (nonatomic, strong) NSNumber *targetNumber;
@property (nonatomic, strong) NSMutableArray<UILabel *> *cellArray;
@property (nonatomic, strong) UILabel *signCell;
@property (nonatomic, assign) CGFloat fontSize;
@property (nonatomic, assign) NSUInteger rowNumber;
@property (nonatomic, strong) NSMutableArray *taskQueue;
@property (nonatomic, assign) BOOL isAnimating;
@property (nonatomic, assign) CGFloat cellWidth;
@property (nonatomic, assign) CGFloat numberCellHeight;
@property (nonatomic, assign) CGFloat signCellHeight;
@property (nonatomic, assign) NSInteger finishedAnimationCount;
@property (nonatomic, assign) NSUInteger maxRowNumber;
@property (nonatomic, strong) UIColor *textColor;
@property (nonatomic, strong) UIFont *font;
@property (nonatomic, assign) SignSetting signSetting;
@property (nonatomic, assign) NSUInteger signRow;
@end
@implementation DPScrollNumberLabel
#pragma mark - Init
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize {
return [self initWithNumber:number fontSize:fontSize textColor:[UIColor grayColor] rowNumber:0];
}
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize textColor:(UIColor *)textColor {
return [self initWithNumber:number fontSize:fontSize textColor:textColor rowNumber:0];
}
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize signSetting:(SignSetting)signSetting {
return [self initWithNumber:number fontSize:fontSize textColor:[UIColor grayColor] signSetting:signSetting];
}
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize rowNumber:(NSUInteger)rowNumber {
return [self initWithNumber:number fontSize:fontSize textColor:[UIColor grayColor] rowNumber:rowNumber];
}
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize textColor:(UIColor *)textColor signSetting:(SignSetting)signSetting {
return [self initWithNumber:number fontSize:fontSize textColor:textColor signSetting:signSetting rowNumber:0];
}
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize textColor:(UIColor *)textColor rowNumber:(NSUInteger)rowNumber {
return [self initWithNumber:number fontSize:fontSize textColor:textColor signSetting:SignSettingUnsigned rowNumber:rowNumber];
}
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize signSetting:(SignSetting)signSetting rowNumber:(NSUInteger)rowNumber {
return [self initWithNumber:number fontSize:fontSize textColor:[UIColor grayColor] signSetting:signSetting rowNumber:rowNumber];
}
- (instancetype)initWithNumber:(NSNumber *)number fontSize:(CGFloat)fontSize textColor:(UIColor *)textColor signSetting:(SignSetting)signSetting rowNumber:(NSUInteger)rowNumber {
self = [super init];
if (self) {
self.targetNumber = number;
self.currentNumber = number;
self.font = [UIFont systemFontOfSize:fontSize];
self.textColor = textColor;
self.isAnimating = NO;
self.finishedAnimationCount = 0;
self.rowNumber = (rowNumber > 0 && rowNumber <= 8) ? rowNumber : 0;
self.maxRowNumber = (self.rowNumber == 0) ? 8 : rowNumber;
self.signSetting = signSetting;
self.minRowNumber = 0;
[self commonInit];
}
return self;
}
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font {
return [self initWithNumber:number font:font textColor:[UIColor grayColor] rowNumber:0];
}
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font textColor:(UIColor *)textColor {
return [self initWithNumber:number font:font textColor:textColor rowNumber:0];
}
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font signSetting:(SignSetting)signSetting {
return [self initWithNumber:number font:font textColor:[UIColor grayColor] signSetting:signSetting rowNumber:0];
}
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font textColor:(UIColor *)textColor signSetting:(SignSetting)signSetting {
return [self initWithNumber:number font:font textColor:textColor signSetting:signSetting rowNumber:0];
}
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font textColor:(UIColor *)textColor rowNumber:(NSUInteger)rowNumber {
return [self initWithNumber:number font:font textColor:textColor signSetting:SignSettingUnsigned rowNumber:rowNumber];
}
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font signSetting:(SignSetting)signSetting rowNumber:(NSUInteger)rowNumber {
return [self initWithNumber:number font:font textColor:[UIColor grayColor] signSetting:signSetting rowNumber:rowNumber];
}
- (instancetype)initWithNumber:(NSNumber *)number font:(UIFont *)font textColor:(UIColor *)textColor signSetting:(SignSetting)signSetting rowNumber:(NSUInteger)rowNumber {
self = [super init];
if (self) {
self.targetNumber = number;
self.currentNumber = number;
self.font = font;
self.textColor = textColor;
self.isAnimating = NO;
self.finishedAnimationCount = 0;
self.rowNumber = (rowNumber > 0 && rowNumber <= 8) ? rowNumber : 0;
self.maxRowNumber = (self.rowNumber == 0) ? 8 : rowNumber;
self.signSetting = signSetting;
[self commonInit];
}
return self;
}
- (void)commonInit {
[self initSign];
[self initCells];
[self initParent];
}
- (void)initSign {
switch (self.signSetting) {
case SignSettingUnsigned:
self.signRow = 0;
int displayedNumber = self.targetNumber.intValue;
if (displayedNumber < 0) {
self.targetNumber = @(abs(displayedNumber));
}
break;
case SignSettingSigned:
case SignSettingNormal:
self.signRow = 1;
break;
default:
break;
}
}
#pragma mark - ConfigViews
- (void)initParent {
self.bounds = CGRectMake(0, 0, (self.rowNumber + self.signRow) * self.cellWidth, self.numberCellHeight / numberCellLineCount);
self.backgroundColor = [UIColor clearColor];
self.layer.masksToBounds = YES;
}
- (void)initCells {
int originNumber = self.targetNumber.intValue;
int sign = originNumber >= 0 ? 1 : -1;
if (self.rowNumber == 0) {
self.rowNumber = [self calculateNumberRow:originNumber];
}
self.cellArray = [[NSMutableArray alloc] init];
CGRect rect = [numberCellText boundingRectWithSize:CGSizeZero
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:self.font}
context:nil];
self.cellWidth = rect.size.width;
self.numberCellHeight = rect.size.height;
self.signCellHeight = rect.size.height * signCellLineCount / numberCellLineCount;
NSArray *displayNumberArray = [self getEachCellValueArrayWithTargetNumber:self.targetNumber.integerValue];
for (NSInteger i = 0; i < self.rowNumber; i++) {
UILabel *numberCell = [self makeNumberCell];
numberCell.frame = CGRectMake((self.rowNumber + self.signRow - 1 - i) * self.cellWidth, 0, self.cellWidth, self.numberCellHeight);
NSNumber *displayNum = [displayNumberArray objectAtIndex:i];
[self moveNumberCell:numberCell toNumber:displayNum.integerValue sign:sign];
[self addSubview:numberCell];
[self.cellArray addObject:numberCell];
}
self.signCell.frame = CGRectMake(0, 0, self.cellWidth, self.signCellHeight);
[self addSubview:self.signCell];
int displayedNumber = self.targetNumber.intValue;
if (displayedNumber > 0) {
[self moveSignCellToSign:SignPositive];
} else if (displayedNumber < 0) {
[self moveSignCellToSign:SignNegative];
} else {
[self moveSignCellToSign:SignZero];
}
}
- (void)updateToRowNumber:(NSInteger)rowNumber {
if (rowNumber == self.rowNumber) {
return;
}
if (rowNumber < self.minRowNumber) {
return;
}
[self removeAllCellFromSuperview];
[self updateCellModelToFitRowNumber:rowNumber];
[self updateCellLayoutToFitRowNumber:rowNumber withAnimation:YES];
self.rowNumber = rowNumber;
}
- (void)removeAllCellFromSuperview {
[self.cellArray makeObjectsPerformSelector:@selector(removeFromSuperview)];
}
- (void)updateCellModelToFitRowNumber:(NSInteger)rowNumber {
if (rowNumber > self.rowNumber) {
for (NSInteger i = self.rowNumber; i < rowNumber; i++) {
UILabel *scrollCell = [self makeNumberCell];
scrollCell.frame = CGRectMake((self.rowNumber + self.signRow - 1 - i) * self.cellWidth, -self.numberCellHeight * 10 / numberCellLineCount, self.cellWidth, self.numberCellHeight);
[self.cellArray addObject:scrollCell];
}
}else {
for (NSInteger i = rowNumber; i < self.rowNumber; i++) {
[self.cellArray removeLastObject];
}
}
}
- (void)updateCellLayoutToFitRowNumber:(NSUInteger)rowNumber withAnimation:(BOOL)animated{
for (UILabel *cell in self.cellArray) {
[self addSubview:cell];
}
__weak typeof(self) weakSelf = self;
NSUInteger interval = 0;
if (rowNumber > self.rowNumber) {
interval = rowNumber - self.rowNumber;
} else {
interval = self.rowNumber - rowNumber;
}
[UIView animateWithDuration:0.5 * interval animations:^{
for (int i = 0; i < rowNumber; i++) {
UILabel *cell = [weakSelf.cellArray objectAtIndex:i];
cell.frame = CGRectMake((rowNumber + self.signRow - 1 - i) * weakSelf.cellWidth,
cell.frame.origin.y,
weakSelf.cellWidth,
weakSelf.numberCellHeight);
}
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
(rowNumber + self.signRow) * self.cellWidth,
self.numberCellHeight/numberCellLineCount);
} completion:nil];
}
#pragma mark - Animation
- (void)playAnimationWithChange:(NSInteger)changeValue previousNumber:(NSNumber *)previousNumber interval:(CGFloat)interval {
BOOL signChanged = NO;
if ((previousNumber.integerValue < 0 && self.targetNumber.integerValue > 0) ||
(previousNumber.integerValue > 0 && self.targetNumber.integerValue < 0)) {
signChanged = YES;
}
int sign = self.targetNumber.intValue >= 0 ? 1 : -1;
if (signChanged) {
sign = previousNumber.intValue >= 0 ? 1 : -1;
CGFloat interval2 = (CGFloat)fabs(self.targetNumber.integerValue * interval / (CGFloat)changeValue);
NSInteger changeValue2 = self.targetNumber.integerValue;
DPAnimationTask *task = [[DPAnimationTask alloc] init];
task.targetNumber = self.targetNumber.integerValue;
task.interval = interval2;
task.changeValue = changeValue2;
@synchronized (self.taskQueue) {
[self.taskQueue addObject:task];
}
changeValue = - previousNumber.integerValue;
interval = interval - interval2;
self.targetNumber = @0;
} else if (previousNumber.intValue == 0) {
[self makeSignChangeAnimation];
} else if (self.targetNumber.intValue == 0) {
sign = previousNumber.intValue >= 0 ? 1 : -1;
[self makeSignChangeAnimation];
}
NSInteger targetRowNumber = [self calculateNumberRow:self.targetNumber.intValue];
if (targetRowNumber > self.rowNumber) {
[self updateToRowNumber:targetRowNumber];
}
NSArray *repeatCountArray = [self getRepeatTimesWithChangeNumber:changeValue targetNumber:self.targetNumber.integerValue];
NSArray *targetDisplayNums = [self getEachCellValueArrayWithTargetNumber:self.targetNumber.integerValue];
if (interval == 0) {
interval = [self getIntervalWithPreviousNumber:previousNumber.integerValue targetNumber:self.targetNumber.integerValue];
}
ScrollAnimationDirection direction = ((changeValue * sign) <= 0)? ScrollAnimationDirectionIncrease : ScrollAnimationDirectionDecrease;
CGFloat delay = 0.0f;
if (repeatCountArray.count != 0) {
for (NSInteger i = 0; i < repeatCountArray.count; i++) {
NSNumber *repeat = [repeatCountArray objectAtIndex:i];
NSInteger repeatCount = repeat.integerValue;
NSNumber *willDisplayNum = [targetDisplayNums objectAtIndex:i];
UILabel *cell = [self.cellArray objectAtIndex:i];
CGFloat startDuration = 0;
if (repeatCount == 0) {
[self makeSingleAnimationWithCell:cell duration:interval delay:delay animationCount:repeatCountArray.count displayNumber:willDisplayNum.integerValue];
} else {
if (direction == ScrollAnimationDirectionIncrease) {
startDuration = interval * (10 - [self getValueOfCell:cell]) / ceilf(fabs(changeValue / pow(10, i)));
CGFloat cycleDuration = interval * 10 / fabs(changeValue / pow(10, i));
if (repeatCount == 1) {
cycleDuration = 0;
}
CGFloat endDuration = bufferModulus * pow(willDisplayNum.integerValue, 0.3) / (i + 1);
DPAnimationAttribute *attribute = [[DPAnimationAttribute alloc] init];
attribute.startDuration = startDuration;
attribute.startDelay = delay;
attribute.cycleDuration = cycleDuration;
attribute.endDuration = endDuration;
attribute.repeatCount = repeatCount - 1;
attribute.targetNumber = willDisplayNum.integerValue;
attribute.sign = sign;
[self makeMultiAnimationWithCell:cell direction:direction animationCount:repeatCountArray.count attribute:attribute];
} else if (direction == ScrollAnimationDirectionDecrease) {
startDuration = interval * ([self getValueOfCell:cell] - 0) / ceilf(fabs(changeValue / pow(10, i)));
CGFloat cycleDuration = interval * 10 / fabs(changeValue / pow(10, i));
if (repeatCount == 1) {
cycleDuration = 0;
}
CGFloat endDuration = bufferModulus * pow(10 - willDisplayNum.integerValue, 0.3) / (i + 1);
DPAnimationAttribute *attribute = [[DPAnimationAttribute alloc] init];
attribute.startDuration = startDuration;
attribute.startDelay = delay;
attribute.cycleDuration = cycleDuration;
attribute.endDuration = endDuration;
attribute.repeatCount = repeatCount - 1;
attribute.targetNumber = willDisplayNum.integerValue;
attribute.sign = sign;
[self makeMultiAnimationWithCell:cell direction:direction animationCount:repeatCountArray.count attribute:attribute];
}
}
delay = delay + startDuration;
}
}
}
- (void)makeMultiAnimationWithCell:(UILabel *)cell
direction:(ScrollAnimationDirection)direction
animationCount:(NSInteger)count
attribute:(DPAnimationAttribute *)attribute{
[UIView animateWithDuration:attribute.startDuration delay:attribute.startDelay options:UIViewAnimationOptionCurveEaseIn animations:^{
[self moveNumberCell:cell toNumber:(direction == ScrollAnimationDirectionIncrease)? 10 : 0 sign:attribute.sign];
} completion:^(BOOL finished) {
NSLog(@"start animation finish!");
[self moveNumberCell:cell toNumber:(direction == ScrollAnimationDirectionIncrease)? 0 : 10 sign:attribute.sign];
if (attribute.cycleDuration == 0) {
[UIView animateWithDuration:attribute.endDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self moveNumberCell:cell toNumber:attribute.targetNumber sign:attribute.sign];
} completion:^(BOOL finished) {
[self oneAnimationDidFinishedWithTotalCount:count];
NSLog(@"end animation finish!");
}];
}else {
[UIView animateWithDuration:attribute.cycleDuration delay:0 options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionRepeat animations:^{
[UIView setAnimationRepeatCount:attribute.repeatCount];
[self moveNumberCell:cell toNumber:(direction == ScrollAnimationDirectionIncrease) ? 10 : 0 sign:attribute.sign];
} completion:^(BOOL finished) {
NSLog(@"cycle animation finish!");
[self moveNumberCell:cell toNumber:(direction == ScrollAnimationDirectionIncrease)?0 : 10 sign:attribute.sign];
[UIView animateWithDuration:attribute.endDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self moveNumberCell:cell toNumber:attribute.targetNumber sign:attribute.sign];
} completion:^(BOOL finished) {
[self oneAnimationDidFinishedWithTotalCount:count];
NSLog(@"end animation finish!");
}];
}];
}
}];
}
- (void)makeSingleAnimationWithCell:(UILabel *)cell duration:(CGFloat)duration delay:(CGFloat)delay animationCount:(NSInteger)count displayNumber:(NSInteger)displayNumber{
int sign = displayNumber >= 0 ? 1 : -1;
[UIView animateWithDuration:duration delay:delay options:UIViewAnimationOptionCurveEaseOut animations:^{
[self moveNumberCell:cell toNumber:displayNumber sign:sign];
} completion:^(BOOL finished) {
[self oneAnimationDidFinishedWithTotalCount:count];
NSLog(@"single animation finish!");
}];
}
- (void)makeSignChangeAnimation {
Sign sign;
if (self.targetNumber.intValue > 0) {
sign = SignPositive;
} else if (self.targetNumber.intValue < 0) {
sign = SignNegative;
} else {
sign = SignZero;
}
[UIView animateWithDuration:0.5 animations:^{
[self moveSignCellToSign:sign];
}];
}
- (void)oneAnimationDidFinishedWithTotalCount:(NSInteger)totalCount {
self.finishedAnimationCount++;
if (self.finishedAnimationCount == totalCount) {
self.finishedAnimationCount = 0;
[self checkTaskArray];
}
}
- (void)checkTaskArray {
@synchronized (self.taskQueue) {
if (self.taskQueue.count != 0) {
DPAnimationTask *task = [self.taskQueue firstObject];
[self.taskQueue removeObject:task];
NSNumber *previousNumber = self.targetNumber;
self.targetNumber = @(task.targetNumber);
[self playAnimationWithChange:task.changeValue previousNumber:previousNumber interval:task.interval];
} else {
self.isAnimating = NO;
NSInteger needNumberRow = [self calculateNumberRow:self.currentNumber.intValue];
if (needNumberRow < self.rowNumber) {
[self updateToRowNumber:needNumberRow];
}
}
}
}
#pragma mark - Public Method
- (void)changeToNumber:(NSNumber *)number animated:(BOOL)animated {
[self changeToNumber:number interval:0 animated:animated];
}
- (void)changeToNumber:(NSNumber *)number interval:(CGFloat)interval animated:(BOOL)animated {
if (self.signSetting == SignSettingUnsigned && number.intValue < 0) {
return ;
}
if ([self calculateNumberRow:number.integerValue] > self.maxRowNumber) {
return ;
}
if (number.integerValue == self.currentNumber.integerValue) {
return ;
}
if (self.isAnimating) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
DPAnimationTask *task = [[DPAnimationTask alloc] init];
task.targetNumber = number.integerValue;
task.changeValue = number.integerValue - self.targetNumber.integerValue;
task.interval = interval;
@synchronized (self.taskQueue) {
[self.taskQueue removeAllObjects];
[self.taskQueue addObject:task];
}
});
} else {
NSNumber *previousNumber = self.targetNumber;
self.targetNumber = number;
if (animated) {
[self playAnimationWithChange:number.integerValue - previousNumber.integerValue previousNumber:previousNumber interval:interval];
self.isAnimating = YES;
} else {
int sign = number.integerValue >= 0 ? 1 : -1;
NSArray<NSNumber *> *displayNumbers = [self getEachCellValueArrayWithTargetNumber:number.integerValue];
for (int i = 0; i < displayNumbers.count; i++) {
[self moveNumberCell:self.cellArray[i] toNumber:displayNumbers[i].integerValue sign:sign];
}
}
}
self.currentNumber = number;
}
#pragma mark - Privite Method
- (NSInteger)calculateNumberRow:(NSInteger)number {
NSInteger numberRow = 1;
while ((number = number / 10) != 0) {
numberRow++;
}
return numberRow;
}
- (void)moveNumberCell:(UILabel *)cell toNumber:(NSInteger)number sign:(NSInteger)sign{
CGFloat x = cell.frame.origin.x;
CGFloat floatNumber = abs((int)number);
CGFloat y = - self.numberCellHeight / numberCellLineCount * 10 - sign * ((CGFloat)floatNumber / numberCellLineCount) * self.numberCellHeight;
cell.frame = CGRectMake(x, y, self.cellWidth, self.numberCellHeight);
}
- (void)moveSignCellToSign:(Sign)sign {
CGFloat x = self.signCell.frame.origin.x;
CGFloat y = - ((CGFloat)sign / signCellLineCount) * self.signCellHeight;
self.signCell.frame = CGRectMake(x, y, self.cellWidth, self.signCellHeight);
}
- (NSArray<NSNumber *> *)getRepeatTimesWithChangeNumber:(NSInteger)change targetNumber:(NSInteger)targetNumber{
NSMutableArray *repeatTimesArray = [[NSMutableArray alloc] init];
NSInteger originNumber = targetNumber - change;
if (change > 0) {
do {
targetNumber = (targetNumber / 10) * 10;
originNumber = (originNumber / 10) * 10;
NSNumber *repeat = @((targetNumber - originNumber) / 10);
[repeatTimesArray addObject:repeat];
targetNumber = targetNumber / 10;
originNumber = originNumber / 10;
} while ((targetNumber - originNumber) != 0);
}else {
do {
targetNumber = (targetNumber / 10) * 10;
originNumber = (originNumber / 10) * 10;
NSNumber *repeat = @((originNumber - targetNumber) / 10);
[repeatTimesArray addObject:repeat];
targetNumber = targetNumber / 10;
originNumber = originNumber / 10;
} while ((originNumber - targetNumber) != 0);
}
return repeatTimesArray;
}
- (NSArray<NSNumber *> *)getEachCellValueArrayWithTargetNumber:(NSInteger)targetNumber {
NSMutableArray *cellValueArray = [[NSMutableArray alloc] init];
NSInteger tmp;
for (NSInteger i = 0; i < self.rowNumber; i++) {
tmp = targetNumber % 10;
NSNumber *number = @(tmp);
[cellValueArray addObject:number];
targetNumber = targetNumber / 10;
}
return cellValueArray;
}
- (NSInteger)getValueOfCell:(UILabel *)cell {
CGFloat y = cell.frame.origin.y;
CGFloat tmpNumber = (- (y * numberCellLineCount / self.numberCellHeight)) - 10;
NSInteger displayNumber = (NSInteger)roundf(tmpNumber);
displayNumber = abs((int)displayNumber);
return displayNumber;
}
- (CGFloat)getIntervalWithPreviousNumber:(NSInteger)previousNumber targetNumber:(NSInteger)targetNumber {
NSArray *repeatTimesArray = [self getRepeatTimesWithChangeNumber:targetNumber - previousNumber targetNumber:targetNumber];
NSUInteger count = repeatTimesArray.count;
NSInteger tmp1 = targetNumber / (NSInteger)pow(10, count - 1);
NSInteger tmp2 = previousNumber / (NSInteger)pow(10, count - 1);
NSInteger maxChangeNum = labs(tmp1 % 10 - tmp2 % 10);
return normalModulus * count * maxChangeNum;
}
#pragma mark - Setters
- (void)setMinRowNumber:(NSUInteger)minRowNumber {
[self updateToRowNumber:minRowNumber];
_minRowNumber = minRowNumber;
}
#pragma mark - Getters
- (UILabel *)makeNumberCell {
UILabel *cell = [[UILabel alloc] init];
cell.font = self.font;
cell.numberOfLines = numberCellLineCount;
// cell.textColor = self.textColor;
cell.dk_textColorPicker = DKColorPickerWithKey(Dk_TITLE);
cell.text = numberCellText;
cell.textAlignment = NSTextAlignmentRight;
return cell;
}
- (UILabel *)signCell {
if (!_signCell) {
_signCell = [[UILabel alloc] init];
_signCell.font = self.font;
_signCell.numberOfLines = signCellLineCount;
switch (self.signSetting) {
case SignSettingNormal:
_signCell.text = @"-\n \n ";
break;
case SignSettingUnsigned:
_signCell.text = @" \n \n ";
break;
case SignSettingSigned:
_signCell.text = @"-\n \n+";
break;
default:
break;
}
_signCell.textColor = self.textColor;
}
return _signCell;
}
- (NSMutableArray *)taskQueue {
if (!_taskQueue) {
_taskQueue = [NSMutableArray arrayWithCapacity:1];
}
return _taskQueue;
}
@end
......@@ -7,17 +7,17 @@
<key>AFNetworking.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>18</integer>
<integer>8</integer>
</dict>
<key>DKNightVersion.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>19</integer>
<integer>10</integer>
</dict>
<key>DOUAudioStreamer.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>16</integer>
<integer>12</integer>
</dict>
<key>FreeStreamer.xcscheme_^#shared#^_</key>
<dict>
......@@ -27,7 +27,7 @@
<key>IQKeyboardManager.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>11</integer>
<integer>5</integer>
</dict>
<key>MBProgressHUD.xcscheme_^#shared#^_</key>
<dict>
......@@ -37,47 +37,47 @@
<key>MJRefresh.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>12</integer>
<integer>13</integer>
</dict>
<key>Masonry.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>10</integer>
<integer>18</integer>
</dict>
<key>Pods-DreamSleep.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>14</integer>
<integer>4</integer>
</dict>
<key>Reachability.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
<integer>7</integer>
</dict>
<key>YYCache.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>7</integer>
<integer>15</integer>
</dict>
<key>YYImage.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>8</integer>
<integer>14</integer>
</dict>
<key>YYModel.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>13</integer>
<integer>16</integer>
</dict>
<key>YYWebImage.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>15</integer>
<integer>19</integer>
</dict>
<key>lottie-ios.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>6</integer>
<integer>11</integer>
</dict>
</dict>
</dict>
......
......@@ -12,7 +12,7 @@
<key>UnityFramework.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
<integer>6</integer>
</dict>
</dict>
</dict>
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!