-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDynamicString.m
More file actions
153 lines (132 loc) · 5.84 KB
/
DynamicString.m
File metadata and controls
153 lines (132 loc) · 5.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//
// DynamicString.m
//
// Created by Matt on 2018/12/20.
// Copyright © 2018 Matt. All rights reserved.
//
#import "DynamicString.h"
#import <objc/runtime.h>
@interface NSString (DynamicDigital)
- (BOOL)isPureInteger;
- (BOOL)isPureDouble;
@end
@implementation NSString (DynamicDigital)
- (BOOL)isPureInteger {
NSScanner *scanner = [NSScanner scannerWithString:self];
NSInteger val;
return [scanner scanInteger:&val] && [scanner isAtEnd];
}
- (BOOL)isPureDouble {
NSScanner *scanner = [NSScanner scannerWithString:self];
double val;
return [scanner scanDouble:&val] && [scanner isAtEnd];
}
@end
@implementation UILabel (DynamicDigital)
- (CGFloat)dynamicDigitalAnimation {
return ((NSNumber *)objc_getAssociatedObject(self, _cmd)).doubleValue;
}
- (void)setDynamicDigitalAnimation:(CGFloat)dynamicDigitalAnimation {
objc_setAssociatedObject(self, @selector(dynamicDigitalAnimation), @(dynamicDigitalAnimation), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (dynamicDigitalAnimation > 0) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method orgin = class_getInstanceMethod([self class], @selector(setText:));
Method new = class_getInstanceMethod([self class], @selector(sw_setText:));
method_exchangeImplementations(orgin, new);
});
}
}
- (dispatch_source_t)dynamicTimer {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setDynamicTimer:(dispatch_source_t)dynamicTimer {
objc_setAssociatedObject(self, @selector(dynamicTimer), dynamicTimer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)sw_setText:(NSString *)text {
if (self.dynamicTimer) {
dispatch_source_cancel(self.dynamicTimer);
self.dynamicTimer = nil;
}
if (self.dynamicDigitalAnimation <= 0) {
[self sw_setText:text];
return;
}
NSString *startDigitalString = self.text, *endDigitalString = text;
if ((!startDigitalString.isPureInteger && !startDigitalString.isPureDouble) ||
(!endDigitalString.isPureInteger && !endDigitalString.isPureDouble) ||
[endDigitalString isEqualToString:startDigitalString]) {
[self sw_setText:text];
return;
}
if (endDigitalString.isPureInteger) {
[self sw_setTextIntergerWithStart:startDigitalString end:endDigitalString];
}else {
[self sw_setTextDoubleWithStart:startDigitalString end:endDigitalString];
}
}
- (void)sw_setTextIntergerWithStart:(NSString *)startDigitalString end:(NSString *)endDigitalString {
NSInteger start = startDigitalString.integerValue;
NSInteger end = endDigitalString.integerValue;
NSInteger offset = end - start;
NSInteger count = labs(offset) <= 60 * self.dynamicDigitalAnimation ? labs(offset) : 60 * self.dynamicDigitalAnimation;
CGFloat rate = (CGFloat)labs(offset) / (CGFloat)count;
CGFloat littleDecimal = rate - (NSInteger)rate;
NSInteger bigPart = nearbyint(littleDecimal * count);
NSInteger smallSegment = (NSInteger)rate;
NSInteger bigSegment = smallSegment + 1;
CGFloat time = self.dynamicDigitalAnimation / count;
self.dynamicTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(self.dynamicTimer, DISPATCH_TIME_NOW, time * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
__block NSInteger index = 0;
__block NSInteger current = start;
dispatch_source_set_event_handler(self.dynamicTimer, ^{
index++;
static NSInteger segment;
segment = index <= bigPart ? bigSegment : smallSegment;
current = offset > 0 ? current + segment : current - segment;
dispatch_async(dispatch_get_main_queue(), ^{
[self sw_setText:[NSString stringWithFormat:@"%ld",current]];
});
if (index >= count) {
dispatch_source_cancel(self.dynamicTimer);
objc_setAssociatedObject(self, _cmd, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
});
dispatch_resume(self.dynamicTimer);
}
- (void)sw_setTextDoubleWithStart:(NSString *)startDigitalString end:(NSString *)endDigitalString {
CGFloat decimalNum = [endDigitalString componentsSeparatedByString:@"."][1].length;
CGFloat powNum = pow(10, [endDigitalString componentsSeparatedByString:@"."][1].length);
CGFloat start = startDigitalString.doubleValue * powNum;
CGFloat end = endDigitalString.doubleValue * powNum;
CGFloat offset = end - start;
CGFloat count = fabs(offset) <= 60 * self.dynamicDigitalAnimation ? fabs(offset) : 60 * self.dynamicDigitalAnimation;
CGFloat rate = fabs(offset) / count;
CGFloat littleDecimal = rate - rate;
CGFloat bigPart = nearbyint(littleDecimal * count);
CGFloat smallSegment = rate;
CGFloat bigSegment = smallSegment + 1;
CGFloat time = self.dynamicDigitalAnimation / count;
self.dynamicTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(self.dynamicTimer, DISPATCH_TIME_NOW, time * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
__block CGFloat index = 0;
__block CGFloat current = start;
dispatch_source_set_event_handler(self.dynamicTimer, ^{
index++;
static CGFloat segment;
segment = index <= bigPart ? bigSegment : smallSegment;
current = offset > 0 ? current + segment : current - segment;
NSLog(@"%lf,%lf/%lf",current,index,count);
NSString *formatText = [NSString stringWithFormat:@"%%.%.0lflf",decimalNum];
dispatch_async(dispatch_get_main_queue(), ^{
[self sw_setText:[NSString stringWithFormat:formatText,current/powNum]];
});
if (index >= count) {
dispatch_source_cancel(self.dynamicTimer);
objc_setAssociatedObject(self, _cmd, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
});
dispatch_resume(self.dynamicTimer);
}
@end