kevin

Finished Circle Chart

  1 +#import <Foundation/Foundation.h>
  2 +#import <UIKit/UIKit.h>
  3 +
  4 +typedef enum {
  5 + UILabelCountingMethodEaseInOut,
  6 + UILabelCountingMethodEaseIn,
  7 + UILabelCountingMethodEaseOut,
  8 + UILabelCountingMethodLinear
  9 +} UILabelCountingMethod;
  10 +
  11 +typedef NSString* (^UICountingLabelFormatBlock)(float value);
  12 +
  13 +
  14 +@interface UICountingLabel : UILabel
  15 +
  16 +@property (nonatomic, strong) NSString *format;
  17 +@property (nonatomic, assign) UILabelCountingMethod method;
  18 +
  19 +@property (nonatomic, copy) UICountingLabelFormatBlock formatBlock;
  20 +@property (nonatomic, copy) void (^completionBlock)();
  21 +
  22 +
  23 +-(void)countFrom:(float)startValue to:(float)endValue;
  24 +-(void)countFrom:(float)startValue to:(float)endValue withDuration:(NSTimeInterval)duration;
  25 +
  26 +@end
  27 +
  1 +#import "UICountingLabel.h"
  2 +
  3 +#if !__has_feature(objc_arc)
  4 +#error UICountingLabel is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
  5 +#endif
  6 +
  7 +#pragma mark - UILabelCounter
  8 +
  9 +// This whole class & subclasses are private to UICountingLabel, which is why they are declared here in the .m file
  10 +
  11 +@interface UILabelCounter : NSObject
  12 +
  13 +-(float)update:(float)t;
  14 +
  15 +@property float rate;
  16 +
  17 +@end
  18 +
  19 +@interface UILabelCounterLinear : UILabelCounter
  20 +
  21 +@end
  22 +
  23 +@interface UILabelCounterEaseIn : UILabelCounter
  24 +
  25 +@end
  26 +
  27 +@interface UILabelCounterEaseOut : UILabelCounter
  28 +
  29 +@end
  30 +
  31 +@interface UILabelCounterEaseInOut : UILabelCounter
  32 +
  33 +@end
  34 +
  35 +@implementation UILabelCounter
  36 +
  37 +-(float)update:(float)t{
  38 + return 0;
  39 +}
  40 +
  41 +@end
  42 +
  43 +@implementation UILabelCounterLinear
  44 +
  45 +-(float)update:(float)t
  46 +{
  47 + return t;
  48 +}
  49 +
  50 +@end
  51 +
  52 +@implementation UILabelCounterEaseIn
  53 +
  54 +-(float)update:(float)t
  55 +{
  56 + return powf(t, self.rate);
  57 +}
  58 +
  59 +@end
  60 +
  61 +@implementation UILabelCounterEaseOut
  62 +
  63 +-(float)update:(float)t{
  64 + return 1.0-powf((1.0-t), self.rate);
  65 +}
  66 +
  67 +@end
  68 +
  69 +@implementation UILabelCounterEaseInOut
  70 +
  71 +-(float) update: (float) t
  72 +{
  73 + int sign =1;
  74 + int r = (int) self.rate;
  75 + if (r % 2 == 0)
  76 + sign = -1;
  77 + t *= 2;
  78 + if (t < 1)
  79 + return 0.5f * powf (t, self.rate);
  80 + else
  81 + return sign*0.5f * (powf (t-2, self.rate) + sign*2);
  82 +}
  83 +
  84 +@end
  85 +
  86 +#pragma mark - UICountingLabel
  87 +
  88 +@interface UICountingLabel ()
  89 +
  90 +@property float startingValue;
  91 +@property float destinationValue;
  92 +@property NSTimeInterval progress;
  93 +@property NSTimeInterval lastUpdate;
  94 +@property NSTimeInterval totalTime;
  95 +@property float easingRate;
  96 +
  97 +@property (nonatomic, strong) UILabelCounter* counter;
  98 +
  99 +@end
  100 +
  101 +@implementation UICountingLabel
  102 +
  103 +-(void)countFrom:(float)value to:(float)endValue
  104 +{
  105 + [self countFrom:value to:endValue withDuration:2.0f];
  106 +}
  107 +
  108 +-(void)countFrom:(float)startValue to:(float)endValue withDuration:(NSTimeInterval)duration
  109 +{
  110 +
  111 + self.easingRate = 3.0f;
  112 + self.startingValue = startValue;
  113 + self.destinationValue = endValue;
  114 + self.progress = 0;
  115 + self.totalTime = duration;
  116 + self.lastUpdate = [NSDate timeIntervalSinceReferenceDate];
  117 +
  118 + if(self.format == nil)
  119 + self.format = @"%f";
  120 +
  121 + switch(self.method)
  122 + {
  123 + case UILabelCountingMethodLinear:
  124 + self.counter = [[UILabelCounterLinear alloc] init];
  125 + break;
  126 + case UILabelCountingMethodEaseIn:
  127 + self.counter = [[UILabelCounterEaseIn alloc] init];
  128 + break;
  129 + case UILabelCountingMethodEaseOut:
  130 + self.counter = [[UILabelCounterEaseOut alloc] init];
  131 + break;
  132 + case UILabelCountingMethodEaseInOut:
  133 + self.counter = [[UILabelCounterEaseInOut alloc] init];
  134 + break;
  135 + }
  136 +
  137 + self.counter.rate = 3.0f;
  138 +
  139 + NSTimer* timer = [NSTimer timerWithTimeInterval:(1.0f/30.0f) target:self selector:@selector(updateValue:) userInfo:nil repeats:YES];
  140 + [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
  141 +}
  142 +
  143 +-(void)updateValue:(NSTimer*)timer
  144 +{
  145 + // update progress
  146 + NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
  147 + self.progress += now - self.lastUpdate;
  148 + self.lastUpdate = now;
  149 +
  150 + if(self.progress >= self.totalTime)
  151 + {
  152 + [timer invalidate];
  153 + self.progress = self.totalTime;
  154 + }
  155 +
  156 + float percent = self.progress / self.totalTime;
  157 + float updateVal =[self.counter update:percent];
  158 + float value = self.startingValue + (updateVal * (self.destinationValue - self.startingValue));
  159 +
  160 +
  161 + if(self.formatBlock != nil)
  162 + {
  163 + self.text = self.formatBlock(value);
  164 + }
  165 + else
  166 + {
  167 + // check if counting with ints - cast to int
  168 + if([self.format rangeOfString:@"%(.*)d" options:NSRegularExpressionSearch].location != NSNotFound || [self.format rangeOfString:@"%(.*)i"].location != NSNotFound )
  169 + {
  170 + self.text = [NSString stringWithFormat:self.format,(int)value];
  171 + }
  172 + else
  173 + {
  174 + self.text = [NSString stringWithFormat:self.format,value];
  175 + }
  176 + }
  177 +
  178 + if(self.progress == self.totalTime && self.completionBlock != nil)
  179 + {
  180 + self.completionBlock();
  181 + self.completionBlock = nil;
  182 + }
  183 +}
  184 +
  185 +@end