diff --git a/.gitignore b/.gitignore index c964cd8..6ac6f61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Xcode # build/ +.build/ +.swiftpm/ *.pbxuser !default.pbxuser *.mode1v3 diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..3fb11d7 --- /dev/null +++ b/Package.swift @@ -0,0 +1,25 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "MBCircularProgressBar", + platforms: [.iOS(.v9)], + products: [ + .library(name: "MBCircularProgressBar", targets: ["MBCircularProgressBar"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "MBCircularProgressBar", + dependencies: [], + path: "Pod/Classes", + publicHeadersPath: ".") + ] +) diff --git a/Pod/Classes/MBCircularProgressBarLayer.h b/Pod/Classes/MBCircularProgressBarLayer.h index 3465f00..8945bca 100644 --- a/Pod/Classes/MBCircularProgressBarLayer.h +++ b/Pod/Classes/MBCircularProgressBarLayer.h @@ -7,6 +7,7 @@ // @import QuartzCore; +@import UIKit; typedef NS_ENUM(NSInteger, MBCircularProgressBarAppearanceType) { MBCircularProgressBarAppearanceTypeOverlaysEmptyLine = 0, @@ -127,12 +128,12 @@ typedef NS_ENUM(NSInteger, MBCircularProgressBarAppearanceType) { /** * The font size of the unit text [0,∞) */ -@property (nonatomic,copy) NSString *unitFontName; +@property (nonatomic,copy) UIFont *unitFont; /** * The name of the font of the unit string */ -@property (nonatomic,copy) NSString *valueFontName; +@property (nonatomic,copy) UIFont *valueFont; /** * Should show unit screen @@ -155,5 +156,11 @@ typedef NS_ENUM(NSInteger, MBCircularProgressBarAppearanceType) { * Default is NO */ @property (nonatomic,assign) BOOL countdown; + +/** + * Draw the progress circle in counter-clockwise fashion. + */ +@property (nonatomic,assign) BOOL counterclockwise; + @end diff --git a/Pod/Classes/MBCircularProgressBarLayer.m b/Pod/Classes/MBCircularProgressBarLayer.m index 0b1718a..ba303d5 100644 --- a/Pod/Classes/MBCircularProgressBarLayer.m +++ b/Pod/Classes/MBCircularProgressBarLayer.m @@ -32,12 +32,13 @@ @implementation MBCircularProgressBarLayer @dynamic progressAppearanceType; @dynamic decimalPlaces; @dynamic valueDecimalFontSize; -@dynamic unitFontName; -@dynamic valueFontName; +@dynamic unitFont; +@dynamic valueFont; @dynamic showUnitString; @dynamic showValueString; @dynamic textOffset; @dynamic countdown; +@dynamic counterclockwise; #pragma mark - Drawing @@ -57,7 +58,7 @@ - (void) drawInContext:(CGContextRef) context{ [self drawProgressBar:rect context:context]; if (self.showValueString){ - [self drawText:rect context:context]; + [self drawText:rect.size context:context]; } UIGraphicsPopContext(); @@ -120,11 +121,27 @@ - (void)drawProgressBar:(CGRect)rect context:(CGContextRef)c{ } CGMutablePathRef arc = CGPathCreateMutable(); - CGPathAddArc(arc, NULL, - center.x, center.y, radius, - (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, - -(self.progressAngle/100.f)*M_PI-((-self.progressRotationAngle/100.f)*2.f+0.5)*M_PI, - YES); + + BOOL clockwise = !self.counterclockwise; + CGFloat rotation = ((-self.progressRotationAngle/100.f)*2.f+0.5)*M_PI; + CGFloat startAngle = (self.progressAngle/100.f)*M_PI - rotation; + CGFloat endAngle = -(self.progressAngle/100.f)*M_PI - rotation; + CGFloat valueAngle = (2.f*M_PI)*(self.progressAngle/100.f)*(100.f-100.f*self.value/self.maxValue)/100.f; + + if (clockwise) + { + CGPathAddArc(arc, NULL, + center.x, center.y, radius, + startAngle - valueAngle, + endAngle, + YES); + } else { + CGPathAddArc(arc, NULL, + center.x, center.y, radius, + endAngle + valueAngle, + startAngle, + NO); + } CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(arc, NULL, @@ -143,52 +160,55 @@ - (void)drawProgressBar:(CGRect)rect context:(CGContextRef)c{ CGPathRelease(strokedArc); } -- (void)drawText:(CGRect)rect context:(CGContextRef)c{ - NSMutableParagraphStyle* textStyle = NSMutableParagraphStyle.defaultParagraphStyle.mutableCopy; - textStyle.alignment = NSTextAlignmentLeft; - - CGFloat valueFontSize = self.valueFontSize == -1 ? CGRectGetHeight(rect)/5 : self.valueFontSize; - - NSDictionary* valueFontAttributes = @{NSFontAttributeName: [UIFont fontWithName: self.valueFontName size:valueFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; - - NSMutableAttributedString *text = [NSMutableAttributedString new]; - - NSString *formatString = [NSString stringWithFormat:@"%%.%df", (int)self.decimalPlaces]; - - NSString* textToPresent; - if (self.countdown) { - textToPresent = [NSString stringWithFormat:formatString, (self.maxValue - self.value)]; - } else { - textToPresent = [NSString stringWithFormat:formatString, self.value]; - } - NSAttributedString* value = [[NSAttributedString alloc] initWithString:textToPresent +- (void)drawText:(CGSize)rectSize context:(CGContextRef)c +{ + NSMutableParagraphStyle* textStyle = NSMutableParagraphStyle.new; + textStyle.alignment = NSTextAlignmentCenter; + + CGFloat valueFontSize = self.valueFontSize == -1 ? rectSize.height/5 : self.valueFontSize; + + NSDictionary* valueFontAttributes = @{NSFontAttributeName: [self.valueFont fontWithSize:valueFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; + + NSMutableAttributedString *text = [NSMutableAttributedString new]; + + NSString *formatString = [NSString stringWithFormat:@"%%.%df", (int)self.decimalPlaces]; + + NSString* textToPresent; + if (self.countdown) { + textToPresent = [NSString stringWithFormat:formatString, (self.maxValue - self.value)]; + } else { + textToPresent = [NSString stringWithFormat:formatString, self.value]; + } + NSAttributedString* value = [[NSAttributedString alloc] initWithString:textToPresent attributes:valueFontAttributes]; - [text appendAttributedString:value]; - - // set the decimal font size - NSUInteger decimalLocation = [text.string rangeOfString:@"."].location; - if (decimalLocation != NSNotFound){ - NSDictionary* valueDecimalFontAttributes = @{NSFontAttributeName: [UIFont fontWithName: self.valueFontName size:self.valueDecimalFontSize == -1 ? valueFontSize : self.valueDecimalFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; - NSRange decimalRange = NSMakeRange(decimalLocation, text.length - decimalLocation); - [text setAttributes:valueDecimalFontAttributes range:decimalRange]; - } - - // ad the unit only if specified - if (self.showUnitString) { - NSDictionary* unitFontAttributes = @{NSFontAttributeName: [UIFont fontWithName: self.unitFontName size:self.unitFontSize == -1 ? CGRectGetHeight(rect)/7 : self.unitFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; - - NSAttributedString* unit = - [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@", self.unitString] attributes:unitFontAttributes]; - [text appendAttributedString:unit]; - } - - CGSize percentSize = [text size]; - CGPoint textCenter = CGPointMake( - CGRectGetMidX(rect)-percentSize.width/2 + self.textOffset.x, - CGRectGetMidY(rect)-percentSize.height/2 + self.textOffset.y - ); - - [text drawAtPoint:textCenter]; + [text appendAttributedString:value]; + + // set the decimal font size + NSUInteger decimalLocation = [text.string rangeOfString:@"."].location; + if (decimalLocation != NSNotFound){ + NSDictionary* valueDecimalFontAttributes = @{NSFontAttributeName: [self.valueFont fontWithSize:self.valueDecimalFontSize == -1 ? valueFontSize : self.valueDecimalFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; + NSRange decimalRange = NSMakeRange(decimalLocation, text.length - decimalLocation); + [text setAttributes:valueDecimalFontAttributes range:decimalRange]; + } + + // ad the unit only if specified + if (self.showUnitString) { + NSDictionary* unitFontAttributes = @{NSFontAttributeName: [self.unitFont fontWithSize:self.unitFontSize == -1 ? rectSize.height/7 : self.unitFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; + + NSAttributedString* unit = + [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"\n%@", self.unitString] attributes:unitFontAttributes]; + [text appendAttributedString:unit]; + } + + CGSize percentSize = [text size]; + CGPoint textCenter = CGPointMake( + rectSize.width/2-percentSize.width/2 + self.textOffset.x, + rectSize.height/2-percentSize.height/2 + self.textOffset.y + ); + + CGRect rect = { textCenter, percentSize }; + + [text drawInRect:rect]; } #pragma mark - Override methods to support animations diff --git a/Pod/Classes/MBCircularProgressBarView.h b/Pod/Classes/MBCircularProgressBarView.h index 425de6f..a931544 100644 --- a/Pod/Classes/MBCircularProgressBarView.h +++ b/Pod/Classes/MBCircularProgressBarView.h @@ -43,7 +43,7 @@ IB_DESIGNABLE /** * The name of the font of the value string */ -@property (nonatomic,copy) IBInspectable NSString *valueFontName; +@property (nonatomic,copy) IBInspectable UIFont *valueFont; /** * The font size of the value text [0,∞) @@ -63,7 +63,7 @@ IB_DESIGNABLE /** * The name of the font of the unit string */ -@property (nonatomic,copy) IBInspectable NSString *unitFontName; +@property (nonatomic,copy) IBInspectable UIFont *unitFont; /** * The font size of the unit text [0,∞) @@ -142,8 +142,13 @@ IB_DESIGNABLE /** - * The bool value to apply to if its counddown or not + * The bool value to apply to if its countdown or not */ @property (nonatomic,assign) IBInspectable BOOL countdown; + +/** + * The bool value to apply if the progress bar should rendered counter-clockwise. + */ +@property (nonatomic,assign) IBInspectable BOOL counterclockwise; @end diff --git a/Pod/Classes/MBCircularProgressBarView.m b/Pod/Classes/MBCircularProgressBarView.m index 8fecc39..7d2fdc7 100644 --- a/Pod/Classes/MBCircularProgressBarView.m +++ b/Pod/Classes/MBCircularProgressBarView.m @@ -63,10 +63,26 @@ -(void)initView:(CGRect)frame{ [self setDecimalPlaces:0]; [self setShowUnitString:YES]; [self setShowValueString:YES]; - [self setValueFontName:@"HelveticaNeue-Thin"]; + [self setValueFont:[UIFont systemFontOfSize:100]]; [self setTextOffset:CGPointMake(0, 0)]; - [self setUnitFontName:@"HelveticaNeue-Thin"]; + [self setUnitFont:[UIFont systemFontOfSize:30 weight:UIFontWeightThin]]; [self setCountdown:NO]; + [self setCounterclockwise:NO]; +} + +- (void)layoutSubviews { + [self.layer setNeedsDisplay]; +} + +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { + [super traitCollectionDidChange:previousTraitCollection]; + + if (@available(iOS 13.0, *)) { + if ([previousTraitCollection hasDifferentColorAppearanceComparedToTraitCollection: self.traitCollection]) { + // redraw layer (dark-mode) + [self.layer setNeedsDisplay]; + } + } } #pragma mark - Getters and Setters for layer properties @@ -265,20 +281,20 @@ -(CGFloat)valueDecimalFontSize{ return self.progressLayer.valueDecimalFontSize; } --(void)setUnitFontName:(NSString *)unitFontName{ - self.progressLayer.unitFontName = unitFontName; +-(void)setUnitFont:(UIFont *)unitFont{ + self.progressLayer.unitFont = unitFont; } --(NSString *)unitFontName{ - return self.progressLayer.unitFontName; +-(UIFont *)unitFont{ + return self.progressLayer.unitFont; } --(void)setValueFontName:(NSString *)valueFontName{ - self.progressLayer.valueFontName = valueFontName; +-(void)setValueFont:(UIFont *)valueFont{ + self.progressLayer.valueFont = valueFont; } --(NSString *)valueFontName{ - return self.progressLayer.valueFontName; +-(UIFont *)valueFont{ + return self.progressLayer.valueFont; } -(void)setShowUnitString:(BOOL)showUnitString{ @@ -304,6 +320,14 @@ -(void)setCountdown:(BOOL)countdown { -(BOOL)countdown { return self.progressLayer.countdown; } + +-(void)setCounterclockwise:(BOOL)counterclockwise { + self.progressLayer.counterclockwise = counterclockwise; +} + +-(BOOL)counterclockwise { + return self.progressLayer.counterclockwise; +} #pragma mark - CALayer diff --git a/README.md b/README.md index bcb1dc0..294b123 100644 --- a/README.md +++ b/README.md @@ -67,9 +67,9 @@ value | CGFloat | The value to be displayed in the center | [0,maxValue] maxValue | CGFloat | The maximum possible value, used to calculate the progress (value/maxValue) | [0,∞) showValueString | BOOL | Should show value string | showUnitString | BOOL | Should show unit string | -valueFontName | NSString | The name of the font of the value string | Any valid font name +valueFont | UIFont | The font of the value string | Any valid font valueFontSize | CGFloat | The font size of the value text | [0,∞) -valueFontName | NSString | The name of the font of the unit string | Any valid font name +unitFont | UIFont | The font of the unit string | Any valid font unitFontSize | CGFloat | The font size of the unit text | [0,∞) unitString | NSString | The string that represents the units, usually % | fontColor | UIColor | The color of the value and unit text |