From 07b7281a31306cef8bdacbf1fa3faeb5b6bd694b Mon Sep 17 00:00:00 2001 From: Rene van den Berg Date: Fri, 13 Nov 2015 17:40:52 +0100 Subject: [PATCH] Visualize 'added value' in a different color --- Pod/Classes/MBCircularProgressBarLayer.h | 6 +++ Pod/Classes/MBCircularProgressBarLayer.m | 56 +++++++++++++++++++++--- Pod/Classes/MBCircularProgressBarView.h | 17 +++++++ Pod/Classes/MBCircularProgressBarView.m | 51 +++++++++++++++++++++ 4 files changed, 124 insertions(+), 6 deletions(-) diff --git a/Pod/Classes/MBCircularProgressBarLayer.h b/Pod/Classes/MBCircularProgressBarLayer.h index b6f75df..7e7b889 100644 --- a/Pod/Classes/MBCircularProgressBarLayer.h +++ b/Pod/Classes/MBCircularProgressBarLayer.h @@ -13,6 +13,7 @@ @property (nonatomic,assign) CGFloat progressAngle; @property (nonatomic,assign) CGFloat progressRotationAngle; @property (nonatomic,assign) CGFloat value; +@property (nonatomic,assign) CGFloat addedValue; @property (nonatomic,assign) CGFloat maxValue; @property (nonatomic,assign) NSTimeInterval animationDuration; @property (nonatomic,assign) BOOL animated; @@ -26,6 +27,11 @@ @property (nonatomic,strong) UIColor *progressStrokeColor; @property (nonatomic,assign) CGLineCap progressCapType; +@property (nonatomic,assign) CGFloat additionLineWidth; +@property (nonatomic,strong) UIColor *additionColor; +@property (nonatomic,strong) UIColor *additionStrokeColor; +@property (nonatomic,assign) NSInteger additionCapType; + @property (nonatomic,assign) CGFloat emptyLineWidth; @property (nonatomic,assign) CGLineCap emptyCapType; @property (nonatomic,strong) UIColor *emptyLineColor; diff --git a/Pod/Classes/MBCircularProgressBarLayer.m b/Pod/Classes/MBCircularProgressBarLayer.m index 13874b3..b20a160 100644 --- a/Pod/Classes/MBCircularProgressBarLayer.m +++ b/Pod/Classes/MBCircularProgressBarLayer.m @@ -13,17 +13,22 @@ @implementation MBCircularProgressBarLayer @dynamic value; +@dynamic addedValue; @dynamic maxValue; @dynamic valueFontSize; @dynamic unitString; @dynamic unitFontSize; @dynamic progressLineWidth; +@dynamic additionLineWidth; @dynamic progressColor; @dynamic progressStrokeColor; +@dynamic additionColor; +@dynamic additionStrokeColor; @dynamic emptyLineWidth; @dynamic progressAngle; @dynamic emptyLineColor; @dynamic emptyCapType; +@dynamic additionCapType; @dynamic progressCapType; @dynamic fontColor; @dynamic progressRotationAngle; @@ -45,6 +50,7 @@ - (void) drawInContext:(CGContextRef) context{ CGSize size = CGRectIntegral(CGContextGetClipBoundingBox(context)).size; [self drawEmptyBar:size context:context]; [self drawProgressBar:size context:context]; + [self drawAdditionBar:size context:context]; if (self.showValueString){ [self drawText:size context:context]; @@ -117,6 +123,42 @@ - (void)drawProgressBar:(CGSize)rectSize context:(CGContextRef)c{ CGPathRelease(strokedArc); } +- (void)drawAdditionBar:(CGSize)rectSize context:(CGContextRef)c{ + if(self.additionLineWidth <= 0){ + return; + } + + CGMutablePathRef arc = CGPathCreateMutable(); + + CGPathAddArc(arc, NULL, + rectSize.width/2, rectSize.height/2, + MIN(rectSize.width,rectSize.height)/2 - self.progressLineWidth, + (self.progressAngle/100.f)*M_PI - + ((-self.progressRotationAngle/100.f)*2.f+0.5)*M_PI - + (2.f*M_PI)*(self.progressAngle/100.f) * (100.f-100.f*(self.value + self.addedValue)/self.maxValue)/100.f, + (self.progressAngle/100.f)*M_PI - + ((-self.progressRotationAngle/100.f)*2.f+0.5)*M_PI - + (2.f*M_PI)*(self.progressAngle/100.f) * (100.f-100.f*self.value/self.maxValue)/100.f, + YES); + + CGPathRef strokedArc = + CGPathCreateCopyByStrokingPath(arc, NULL, + self.additionLineWidth, + (CGLineCap)self.additionCapType, + kCGLineJoinMiter, + 10); + + + CGContextAddPath(c, strokedArc); + CGContextSetFillColorWithColor(c, self.additionColor.CGColor); + CGContextSetStrokeColorWithColor(c, self.additionStrokeColor.CGColor); + CGContextDrawPath(c, kCGPathFillStroke); + + CGPathRelease(arc); + CGPathRelease(strokedArc); +} + + - (void)drawText:(CGSize)rectSize context:(CGContextRef)c { @@ -131,8 +173,10 @@ - (void)drawText:(CGSize)rectSize context:(CGContextRef)c NSMutableAttributedString *text = [NSMutableAttributedString new]; NSString *formatString = [NSString stringWithFormat:@"%%.%df", (int)self.decimalPlaces]; + + CGFloat valueToDisplay = self.value + self.addedValue; NSAttributedString* value = - [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:formatString, self.value] attributes:valueFontAttributes]; + [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:formatString, valueToDisplay] attributes:valueFontAttributes]; [text appendAttributedString:value]; @@ -163,19 +207,19 @@ - (void)drawText:(CGSize)rectSize context:(CGContextRef)c #pragma mark - Override methods to support animations + (BOOL)needsDisplayForKey:(NSString *)key { - if ([key isEqualToString:@"value"]) { + if ([key isEqualToString:@"value"] || [key isEqualToString:@"addedValue"]) { return YES; } return [super needsDisplayForKey:key]; } - (id)actionForKey:(NSString *)event{ - if ([self presentationLayer] != nil) { - if ([event isEqualToString:@"value"] && self.animated) { + if ([self presentationLayer] != nil && self.animated) { + if ([event isEqualToString:@"value"] || [event isEqualToString:@"addedValue"]) { CABasicAnimation *anim = [CABasicAnimation - animationWithKeyPath:@"value"]; + animationWithKeyPath:event]; anim.fromValue = [[self presentationLayer] - valueForKey:@"value"]; + valueForKey:event]; anim.duration = self.animationDuration; return anim; } diff --git a/Pod/Classes/MBCircularProgressBarView.h b/Pod/Classes/MBCircularProgressBarView.h index fd63087..390c5c7 100644 --- a/Pod/Classes/MBCircularProgressBarView.h +++ b/Pod/Classes/MBCircularProgressBarView.h @@ -17,6 +17,9 @@ IB_DESIGNABLE /* The value of the progress bar */ @property (nonatomic,assign) IBInspectable CGFloat value; +/* The added value of the progress bar - the 'delta' section */ +@property (nonatomic,assign) IBInspectable CGFloat addedValue; + /* The maximum possible value, used to calculate the progress (value/maxValue) [0,∞) */ @property (nonatomic,assign) IBInspectable CGFloat maxValue; @@ -65,6 +68,18 @@ IB_DESIGNABLE /* The shape of the progress bar cap {kCGLineCapButt=0, kCGLineCapRound=1, kCGLineCapSquare=2} */ @property (nonatomic,assign) IBInspectable NSInteger progressCapType; +/* The width of the current addition bar (user space units) [0,∞) */ +@property (nonatomic,assign) IBInspectable CGFloat additionLineWidth; + +/* The color of the current addition bar */ +@property (nonatomic,strong) IBInspectable UIColor *additionColor; + +/* The color of the current addition bar frame */ +@property (nonatomic,strong) IBInspectable UIColor *additionStrokeColor; + +/* The shape of the current addition bar cap {kCGLineCapButt=0, kCGLineCapRound=1, kCGLineCapSquare=2} */ +@property (nonatomic,assign) IBInspectable NSInteger additionCapType; + /* The width of the background bar (user space units) [0,∞) */ @property (nonatomic,assign) IBInspectable CGFloat emptyLineWidth; @@ -77,4 +92,6 @@ IB_DESIGNABLE /* Set the value of the progress bar with animation */ -(void)setValue:(CGFloat)value animateWithDuration:(NSTimeInterval)duration; +/* Set the value of the delta section of the progress bar with animation */ +-(void)setAddedValue:(CGFloat)addedValue animateWithDuration:(NSTimeInterval)duration; @end diff --git a/Pod/Classes/MBCircularProgressBarView.m b/Pod/Classes/MBCircularProgressBarView.m index cae8c48..756c585 100644 --- a/Pod/Classes/MBCircularProgressBarView.m +++ b/Pod/Classes/MBCircularProgressBarView.m @@ -43,11 +43,14 @@ -(void)initView:(CGRect)frame{ [self setUnitString:@"%"]; [self setValue:0.f]; + [self setAddedValue:0.f]; [self setMaxValue:100.f]; [self setProgressRotationAngle:0.f]; [self setProgressStrokeColor:[UIColor orangeColor]]; + [self setAdditionStrokeColor:[UIColor yellowColor]]; [self setProgressColor:[UIColor orangeColor]]; [self setProgressCapType:kCGLineCapRound]; + [self setAdditionCapType:kCGLineCapRound]; [self setEmptyLineColor:[UIColor lightGrayColor]]; [self setFontColor:[UIColor blackColor]]; [self setEmptyLineWidth:1.f]; @@ -85,6 +88,17 @@ -(void)setValue:(CGFloat)value{ } } +-(void)setAddedValue:(CGFloat)addedValue{ + [self progressLayer].animated = NO; + + self.progressLayer.addedValue = addedValue; + + //CALayer autogenerated setter using @dynamic doesn't refresh the layer when the value is 0 + if(addedValue == 0){ + [self.layer setNeedsDisplay]; + } +} + -(CGFloat)value{ return self.progressLayer.value; } @@ -118,6 +132,14 @@ -(CGFloat)emptyLineWidth{ return self.progressLayer.emptyLineWidth; } +-(void)setAdditionLineWidth:(CGFloat)additionLineWidth{ + self.progressLayer.additionLineWidth = additionLineWidth; +} + +-(CGFloat)additionLineWidth{ + return self.progressLayer.additionLineWidth; +} + -(void)setProgressColor:(UIColor*)color{ self.progressLayer.progressColor = color; } @@ -125,6 +147,13 @@ -(void)setProgressColor:(UIColor*)color{ -(UIColor*)progressColor{ return self.progressLayer.progressColor; } +-(void)setAdditionColor:(UIColor *)additionColor{ + self.progressLayer.additionColor = additionColor; +} + +-(UIColor *)additionColor{ + return self.progressLayer.additionColor; +} -(void)setUnitFontSize:(CGFloat)unitFontSize{ self.progressLayer.unitFontSize = unitFontSize; @@ -166,6 +195,14 @@ -(UIColor*)progressStrokeColor{ return self.progressLayer.progressStrokeColor; } +-(void)setAdditionStrokeColor:(UIColor *)additionStrokeColor{ + self.progressLayer.additionStrokeColor = additionStrokeColor; +} + +-(UIColor *)additionStrokeColor{ + return self.progressLayer.additionStrokeColor; +} + -(void)setEmptyLineColor:(UIColor *)emptyLineColor{ self.progressLayer.emptyLineColor = emptyLineColor; } @@ -206,6 +243,14 @@ -(NSInteger)EmptyCapType{ return self.progressLayer.emptyCapType; } +-(void)setAdditionCapType:(NSInteger)additionCapType{ + self.progressLayer.additionCapType = additionCapType; +} + +-(NSInteger)additionCapType{ + return self.progressLayer.additionCapType; +} + -(CGLineCap)safeCapType:(NSInteger)type{ if(kCGLineCapButt <= type && type <= kCGLineCapSquare){ return (CGLineCap)type; @@ -271,4 +316,10 @@ -(void)setValue:(CGFloat)value animateWithDuration:(NSTimeInterval)duration{ [self progressLayer].value = value; } +-(void)setAddedValue:(CGFloat)addedValue animateWithDuration:(NSTimeInterval)duration{ + [self progressLayer].animationDuration = duration; + [self progressLayer].animated = YES; + [self progressLayer].addedValue = addedValue; +} + @end