From d1168f9e0a0d5133b7e5eeb95cd5d06a02a1a2b6 Mon Sep 17 00:00:00 2001 From: John Wu Date: Tue, 8 Jan 2019 10:26:52 -0500 Subject: [PATCH] Refactored TRCircularProgressLayer to swift --- .../Tropos/Views/CircularProgressLayer.swift | 73 ++++++++++++++ .../Tropos/Views/TRCircularProgressLayer.h | 9 -- .../Tropos/Views/TRCircularProgressLayer.m | 96 ------------------- Sources/Tropos/Views/TRRefreshView.m | 2 +- Tropos.xcodeproj/project.pbxproj | 10 +- 5 files changed, 78 insertions(+), 112 deletions(-) create mode 100644 Sources/Tropos/Views/CircularProgressLayer.swift delete mode 100644 Sources/Tropos/Views/TRCircularProgressLayer.h delete mode 100644 Sources/Tropos/Views/TRCircularProgressLayer.m diff --git a/Sources/Tropos/Views/CircularProgressLayer.swift b/Sources/Tropos/Views/CircularProgressLayer.swift new file mode 100644 index 0000000..a5f84e1 --- /dev/null +++ b/Sources/Tropos/Views/CircularProgressLayer.swift @@ -0,0 +1,73 @@ +import UIKit + +@objc(TRCircularProgressLayer) class CircularProgressLayer: CALayer { + @objc var progress: CGFloat = CGFloat(0) + @objc var radius = CGFloat(15.0) + @objc let outerRingWidth = CGFloat(3.0) + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override init() { + super.init() + self.actions = [ + "bounds": NSNull(), + "contents": NSNull(), + "position": NSNull(), + ] + self.contentsScale = UIScreen.main.scale + self.needsDisplayOnBoundsChange = true + } + + init(layer: CircularProgressLayer) { + super.init(layer: layer) + progress = layer.progress + radius = layer.radius + } + + override func draw(in ctx: CGContext) { + let center = CGPoint(x: self.bounds.width / 2.0, y: self.bounds.height / 2.0) + let progress = min(self.progress, 1.0 - CGFloat.ulpOfOne) + let radians = (progress * .pi * 2.0) - .pi + + ctx.setFillColor(self.backgroundColor ?? UIColor.black.cgColor) + ctx.fill(bounds) + ctx.setBlendMode(.clear) + ctx.setLineWidth(CGFloat(outerRingWidth)) + ctx.setStrokeColor(UIColor.clear.cgColor) + ctx.addArc( + center: center, + radius: CGFloat(radius), + startAngle: 0.0, + endAngle: 2 * .pi, + clockwise: false + ) + ctx.strokePath() + + if progress > 0.0 { + ctx.setFillColor(UIColor.clear.cgColor) + let progressPath = CGMutablePath() + progressPath.move(to: center) + progressPath.addArc( + center: center, + radius: CGFloat(self.radius), + startAngle: 3.0 * .pi, + endAngle: radians, + clockwise: false + ) + ctx.closePath() + ctx.addPath(progressPath) + ctx.fillPath() + } + } + + override class func needsDisplay(forKey key: String) -> Bool { + switch key { + case "progress", "radius", "outerRingWidth": + return true + default: + return false + } + } +} diff --git a/Sources/Tropos/Views/TRCircularProgressLayer.h b/Sources/Tropos/Views/TRCircularProgressLayer.h deleted file mode 100644 index 8646824..0000000 --- a/Sources/Tropos/Views/TRCircularProgressLayer.h +++ /dev/null @@ -1,9 +0,0 @@ -@import UIKit; - -@interface TRCircularProgressLayer : CALayer - -@property (nonatomic) CGFloat progress; -@property (nonatomic) CGFloat radius; -@property (nonatomic) CGFloat outerRingWidth; - -@end diff --git a/Sources/Tropos/Views/TRCircularProgressLayer.m b/Sources/Tropos/Views/TRCircularProgressLayer.m deleted file mode 100644 index 441ce1e..0000000 --- a/Sources/Tropos/Views/TRCircularProgressLayer.m +++ /dev/null @@ -1,96 +0,0 @@ -#import "TRCircularProgressLayer.h" - -static CGPoint TRCGPointMakeIntegral(CGFloat x, CGFloat y) { - return CGPointMake((CGFloat)round(x), (CGFloat)round(y)); - -} - -@implementation TRCircularProgressLayer - -@dynamic progress, radius; - -#pragma mark - Initialization - -- (instancetype)init -{ - self = [super init]; - if (!self) return nil; - - self.actions = @{@"bounds": [NSNull null], @"contents": [NSNull null], @"position": [NSNull null]}; - self.contentsScale = [UIScreen mainScreen].scale; - self.needsDisplayOnBoundsChange = YES; - self.outerRingWidth = 3.0f; - self.radius = 15.0f; - - return self; -} - -- (instancetype)initWithLayer:(TRCircularProgressLayer *)layer -{ - self = [super initWithLayer:layer]; - if (!self) return nil; - if (![layer isKindOfClass:[TRCircularProgressLayer class]]) return self; - - self.progress = layer.progress; - self.radius = layer.radius; - - return self; -} - -#pragma mark - CALayer - -- (void)drawInContext:(CGContextRef)context -{ - CGPoint center = TRCGPointMakeIntegral(CGRectGetWidth(self.bounds) / 2.0f, CGRectGetHeight(self.bounds) / 2.0f); - - CGFloat progress = MIN(self.progress, 1.0f - FLT_EPSILON); - CGFloat radians = (progress * (CGFloat)M_PI * 2.0f) - (CGFloat)M_PI_2; - - CGContextSetFillColorWithColor(context, self.backgroundColor); - CGContextFillRect(context, self.bounds); - - CGContextSetBlendMode(context, kCGBlendModeClear); - - CGContextSetLineWidth(context, self.outerRingWidth); - CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]); - CGContextAddArc(context, center.x, center.y, self.radius, 0.0f, (CGFloat)M_PI * 2, YES); - CGContextStrokePath(context); - - if (progress > 0.0f) { - CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]); - CGMutablePathRef progressPath = CGPathCreateMutable(); - CGPathMoveToPoint(progressPath, NULL, center.x, center.y); - CGPathAddArc(progressPath, NULL, center.x, center.y, self.radius, 3.0f * (CGFloat)M_PI_2, radians, false); - CGPathCloseSubpath(progressPath); - CGContextAddPath(context, progressPath); - CGContextFillPath(context); - CGPathRelease(progressPath); - } -} - -+ (BOOL)needsDisplayForKey:(NSString *)key -{ - if ([[self animatableKeys] containsObject:key]) { - return YES; - } - - return [super needsDisplayForKey:key]; -} - -#pragma mark - Private - -+ (NSSet *)animatableKeys -{ - static NSSet *keys; - - if (!keys) { - NSString *progressKey = NSStringFromSelector(@selector(progress)); - NSString *maskRadiusKey = NSStringFromSelector(@selector(radius)); - NSString *outerRingWidthKey = NSStringFromSelector(@selector(outerRingWidth)); - keys = [[NSSet alloc] initWithObjects:progressKey, maskRadiusKey, outerRingWidthKey, nil]; - } - - return keys; -} - -@end diff --git a/Sources/Tropos/Views/TRRefreshView.m b/Sources/Tropos/Views/TRRefreshView.m index efc29d6..ad2ae91 100644 --- a/Sources/Tropos/Views/TRRefreshView.m +++ b/Sources/Tropos/Views/TRRefreshView.m @@ -1,5 +1,5 @@ +#import "Tropos-Swift.h" #import "TRRefreshView.h" -#import "TRCircularProgressLayer.h" #import "TRColorBackdropLayer.h" #import "TRRefreshLayer.h" diff --git a/Tropos.xcodeproj/project.pbxproj b/Tropos.xcodeproj/project.pbxproj index ee98ddf..43ce37f 100644 --- a/Tropos.xcodeproj/project.pbxproj +++ b/Tropos.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 0F9A6CB421C9A9D40035C811 /* CLLocation+TRRecentLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F9A6CB121C996EC0035C811 /* CLLocation+TRRecentLocation.swift */; }; 0F9A6CBA21CBF4C30035C811 /* LocationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F9A6CB921CBF4C30035C811 /* LocationController.swift */; }; + 0FB1907821E3AF8900A2A8CA /* CircularProgressLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB1907721E3AF8800A2A8CA /* CircularProgressLayer.swift */; }; 4A21D76820C9E6FA0055A2AF /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A21D76720C9E6FA0055A2AF /* IntentHandler.swift */; }; 4A21D76C20C9E6FB0055A2AF /* TroposIntents.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 4A21D76520C9E6FA0055A2AF /* TroposIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 4A5109D520C9CB8100F993FC /* INInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A5109D420C9CB8100F993FC /* INInteraction.swift */; }; @@ -114,7 +115,6 @@ 4D1ABA0B1A89686200B7F8FB /* TRNavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1ABA0A1A89686200B7F8FB /* TRNavigationBar.m */; }; 4D3336F61A80BE16001BA9A8 /* TRDailyForecastView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4D3336F51A80BE16001BA9A8 /* TRDailyForecastView.xib */; }; 4D49554C1A8C298A0066F278 /* TRRefreshView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D49554B1A8C298A0066F278 /* TRRefreshView.m */; }; - 4D49554F1A8C29C30066F278 /* TRCircularProgressLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D49554E1A8C29C30066F278 /* TRCircularProgressLayer.m */; }; 4D4955521A8C2B5D0066F278 /* UIImage+TRColorBackdrop.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D4955511A8C2B5D0066F278 /* UIImage+TRColorBackdrop.m */; }; 4D7389DF1A9890CD0039F13B /* UIScrollView+TRReactiveCocoa.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7389DE1A9890CD0039F13B /* UIScrollView+TRReactiveCocoa.m */; }; 4D76CCD41A99C3FA00DDE5EB /* TRRefreshLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D76CCD31A99C3FA00DDE5EB /* TRRefreshLayer.m */; }; @@ -241,6 +241,7 @@ 0B30A1610CAE1C2E302C28B0 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0F9A6CB121C996EC0035C811 /* CLLocation+TRRecentLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CLLocation+TRRecentLocation.swift"; sourceTree = ""; }; 0F9A6CB921CBF4C30035C811 /* LocationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationController.swift; sourceTree = ""; }; + 0FB1907721E3AF8800A2A8CA /* CircularProgressLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularProgressLayer.swift; sourceTree = ""; }; 1CDD2312F1EF05277F045E15 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22FE01C01AF3F5550085B494 /* Secrets.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Secrets.h; sourceTree = ""; }; 449386DA1B5044EE00766EC9 /* pl-PL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pl-PL"; path = "pl-PL.lproj/Localizable.strings"; sourceTree = ""; }; @@ -348,8 +349,6 @@ 4D3336F51A80BE16001BA9A8 /* TRDailyForecastView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TRDailyForecastView.xib; sourceTree = ""; }; 4D49554A1A8C298A0066F278 /* TRRefreshView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TRRefreshView.h; sourceTree = ""; }; 4D49554B1A8C298A0066F278 /* TRRefreshView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TRRefreshView.m; sourceTree = ""; }; - 4D49554D1A8C29C30066F278 /* TRCircularProgressLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TRCircularProgressLayer.h; sourceTree = ""; }; - 4D49554E1A8C29C30066F278 /* TRCircularProgressLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TRCircularProgressLayer.m; sourceTree = ""; }; 4D4955501A8C2B5D0066F278 /* UIImage+TRColorBackdrop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+TRColorBackdrop.h"; sourceTree = ""; }; 4D4955511A8C2B5D0066F278 /* UIImage+TRColorBackdrop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+TRColorBackdrop.m"; sourceTree = ""; }; 4D7389DD1A9890CD0039F13B /* UIScrollView+TRReactiveCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+TRReactiveCocoa.h"; sourceTree = ""; }; @@ -781,10 +780,9 @@ 639AAB142C96B59FC995CA1D /* Views */ = { isa = PBXGroup; children = ( + 0FB1907721E3AF8800A2A8CA /* CircularProgressLayer.swift */, 51FEC99D21CD9F3300CDBC97 /* FadingImageView.swift */, 51FEC99921CD9AC500CDBC97 /* FadingLabel.swift */, - 4D49554D1A8C29C30066F278 /* TRCircularProgressLayer.h */, - 4D49554E1A8C29C30066F278 /* TRCircularProgressLayer.m */, 4DC069CB1A95B8F800F3BCEB /* TRColorBackdropLayer.h */, 4DC069CC1A95B8F800F3BCEB /* TRColorBackdropLayer.m */, 4D98E9831A80C43F00856412 /* TRDailyForecastView.h */, @@ -1325,7 +1323,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4D49554F1A8C29C30066F278 /* TRCircularProgressLayer.m in Sources */, 4D7389DF1A9890CD0039F13B /* UIScrollView+TRReactiveCocoa.m in Sources */, 4AA138C42134835A0083B816 /* Intents.intentdefinition in Sources */, 4DC069CD1A95B8F800F3BCEB /* TRColorBackdropLayer.m in Sources */, @@ -1334,6 +1331,7 @@ 4DDF65061AB3AC0C00909D67 /* TRWeatherController.m in Sources */, 4ACA584B1CC526D600DD0CDC /* RACSignal+TROperators.m in Sources */, 4A86FB65205C0E4D00E761C3 /* AppDelegate.swift in Sources */, + 0FB1907821E3AF8900A2A8CA /* CircularProgressLayer.swift in Sources */, A10109001D336C9C0024B1BA /* TRTableViewCell.swift in Sources */, 4D49554C1A8C298A0066F278 /* TRRefreshView.m in Sources */, A12FCE251D336FA90062E7F1 /* Color.swift in Sources */,