123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- #import "UICountingLabel.h"
- #if !__has_feature(objc_arc)
- #error UICountingLabel is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
- #endif
- #pragma mark - UILabelCounter
- // This whole class & subclasses are private to UICountingLabel, which is why they are declared here in the .m file
- @interface UILabelCounter : NSObject
- -(float)update:(float)t;
- @property float rate;
- @end
- @interface UILabelCounterLinear : UILabelCounter
- @end
- @interface UILabelCounterEaseIn : UILabelCounter
- @end
- @interface UILabelCounterEaseOut : UILabelCounter
- @end
- @interface UILabelCounterEaseInOut : UILabelCounter
- @end
- @implementation UILabelCounter
- -(float)update:(float)t{
- return 0;
- }
- @end
- @implementation UILabelCounterLinear
- -(float)update:(float)t
- {
- return t;
- }
- @end
- @implementation UILabelCounterEaseIn
- -(float)update:(float)t
- {
- return powf(t, self.rate);
- }
- @end
- @implementation UILabelCounterEaseOut
- -(float)update:(float)t{
- return 1.0-powf((1.0-t), self.rate);
- }
- @end
- @implementation UILabelCounterEaseInOut
- -(float) update: (float) t
- {
- int sign =1;
- int r = (int) self.rate;
- if (r % 2 == 0)
- sign = -1;
- t *= 2;
- if (t < 1)
- return 0.5f * powf (t, self.rate);
- else
- return sign*0.5f * (powf (t-2, self.rate) + sign*2);
- }
- @end
- #pragma mark - UICountingLabel
- @interface UICountingLabel ()
- @property float startingValue;
- @property float destinationValue;
- @property NSTimeInterval progress;
- @property NSTimeInterval lastUpdate;
- @property NSTimeInterval totalTime;
- @property float easingRate;
- @property (nonatomic, weak) NSTimer *timer;
- @property (nonatomic, strong) UILabelCounter *counter;
- @end
- @implementation UICountingLabel
- -(void)countFrom:(float)value to:(float)endValue {
-
- if (self.animationDuration == 0.0f) {
- self.animationDuration = 2.0f;
- }
-
- [self countFrom:value to:endValue withDuration:self.animationDuration];
- }
- -(void)countFrom:(float)startValue to:(float)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 setTextValue:endValue];
- [self runCompletionBlock];
- return;
- }
- self.easingRate = 3.0f;
- self.progress = 0;
- self.totalTime = duration;
- self.lastUpdate = [NSDate timeIntervalSinceReferenceDate];
- if(self.format == nil)
- self.format = @"%f";
- switch(self.method)
- {
- case UILabelCountingMethodLinear:
- self.counter = [[UILabelCounterLinear alloc] init];
- break;
- case UILabelCountingMethodEaseIn:
- self.counter = [[UILabelCounterEaseIn alloc] init];
- break;
- case UILabelCountingMethodEaseOut:
- self.counter = [[UILabelCounterEaseOut alloc] init];
- break;
- case UILabelCountingMethodEaseInOut:
- self.counter = [[UILabelCounterEaseInOut alloc] init];
- break;
- }
- self.counter.rate = 3.0f;
- NSTimer *timer = [NSTimer timerWithTimeInterval:(1.0f/30.0f) target:self selector:@selector(updateValue:) userInfo:nil repeats:YES];
- [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
- [[NSRunLoop mainRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
- self.timer = timer;
- }
- - (void)countFromCurrentValueTo:(float)endValue {
- [self countFrom:[self currentValue] to:endValue];
- }
- - (void)countFromCurrentValueTo:(float)endValue withDuration:(NSTimeInterval)duration {
- [self countFrom:[self currentValue] to:endValue withDuration:duration];
- }
- - (void)countFromZeroTo:(float)endValue {
- [self countFrom:0.0f to:endValue];
- }
- - (void)countFromZeroTo:(float)endValue withDuration:(NSTimeInterval)duration {
- [self countFrom:0.0f to:endValue withDuration:duration];
- }
- - (void)updateValue:(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 setTextValue:[self currentValue]];
-
- if (self.progress == self.totalTime) {
- [self runCompletionBlock];
- }
- }
- - (void)setTextValue:(float)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
- {
- self.text = [NSString stringWithFormat:self.format,value];
- }
- }
- }
- - (void)setFormat:(NSString *)format {
- _format = format;
- // update label with new format
- [self setTextValue:self.currentValue];
- }
- - (void)runCompletionBlock {
-
- if (self.completionBlock) {
- self.completionBlock();
- self.completionBlock = nil;
- }
- }
- - (CGFloat)currentValue {
-
- if (self.progress >= self.totalTime) {
- return self.destinationValue;
- }
-
- CGFloat percent = self.progress / self.totalTime;
- CGFloat updateVal = [self.counter update:percent];
- return self.startingValue + (updateVal * (self.destinationValue - self.startingValue));
- }
- @end
|