Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt to changes in frame size #64

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Xcode
#
build/
.build/
.swiftpm/
*.pbxuser
!default.pbxuser
*.mode1v3
Expand Down
25 changes: 25 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -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: ".")
]
)
11 changes: 9 additions & 2 deletions Pod/Classes/MBCircularProgressBarLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

@import QuartzCore;
@import UIKit;

typedef NS_ENUM(NSInteger, MBCircularProgressBarAppearanceType) {
MBCircularProgressBarAppearanceTypeOverlaysEmptyLine = 0,
Expand Down Expand Up @@ -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
Expand All @@ -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
126 changes: 73 additions & 53 deletions Pod/Classes/MBCircularProgressBarLayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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();
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
11 changes: 8 additions & 3 deletions Pod/Classes/MBCircularProgressBarView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,∞)
Expand All @@ -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,∞)
Expand Down Expand Up @@ -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
44 changes: 34 additions & 10 deletions Pod/Classes/MBCircularProgressBarView.m
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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{
Expand All @@ -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

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down