From 207473182e3c699643bbe6b18370204a92f03f95 Mon Sep 17 00:00:00 2001 From: Mitchell Hudson Date: Sun, 15 Jan 2017 15:44:00 -0800 Subject: [PATCH 1/2] Update to Swift 3 Initial conversion to Swift 3 from original project. --- BWCircularSlider.xcodeproj/project.pbxproj | 3 + .../UserInterfaceState.xcuserstate | Bin 0 -> 11075 bytes .../xcschemes/BWCircularSlider.xcscheme | 91 ++++++++++++++ .../xcschemes/xcschememanagement.plist | 22 ++++ TB_CustomControlsSwift/AppDelegate.swift | 12 +- TB_CustomControlsSwift/BWCircularSlider.swift | 114 +++++++++--------- .../BWCircularSliderView.swift | 10 +- 7 files changed, 184 insertions(+), 68 deletions(-) create mode 100644 BWCircularSlider.xcodeproj/project.xcworkspace/xcuserdata/mitchellhudson.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 BWCircularSlider.xcodeproj/xcuserdata/mitchellhudson.xcuserdatad/xcschemes/BWCircularSlider.xcscheme create mode 100644 BWCircularSlider.xcodeproj/xcuserdata/mitchellhudson.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/BWCircularSlider.xcodeproj/project.pbxproj b/BWCircularSlider.xcodeproj/project.pbxproj index 9058bd6..6ba642d 100644 --- a/BWCircularSlider.xcodeproj/project.pbxproj +++ b/BWCircularSlider.xcodeproj/project.pbxproj @@ -137,6 +137,7 @@ TargetAttributes = { DAEB2FAD1A0827EE002EE5EF = { CreatedOnToolsVersion = 6.0.1; + LastSwiftMigration = 0820; }; }; }; @@ -289,6 +290,7 @@ INFOPLIST_FILE = TB_CustomControlsSwift/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = BWCircularSlider; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -299,6 +301,7 @@ INFOPLIST_FILE = TB_CustomControlsSwift/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = BWCircularSlider; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/BWCircularSlider.xcodeproj/project.xcworkspace/xcuserdata/mitchellhudson.xcuserdatad/UserInterfaceState.xcuserstate b/BWCircularSlider.xcodeproj/project.xcworkspace/xcuserdata/mitchellhudson.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..59bf57858a2587d70fa8078f1a49cd011f6a67d4 GIT binary patch literal 11075 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BWCircularSlider.xcodeproj/xcuserdata/mitchellhudson.xcuserdatad/xcschemes/xcschememanagement.plist b/BWCircularSlider.xcodeproj/xcuserdata/mitchellhudson.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..ea5008e --- /dev/null +++ b/BWCircularSlider.xcodeproj/xcuserdata/mitchellhudson.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + BWCircularSlider.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + DAEB2FAD1A0827EE002EE5EF + + primary + + + + + diff --git a/TB_CustomControlsSwift/AppDelegate.swift b/TB_CustomControlsSwift/AppDelegate.swift index eb78c32..ba8e326 100644 --- a/TB_CustomControlsSwift/AppDelegate.swift +++ b/TB_CustomControlsSwift/AppDelegate.swift @@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/TB_CustomControlsSwift/BWCircularSlider.swift b/TB_CustomControlsSwift/BWCircularSlider.swift index c1945a4..b74afe7 100644 --- a/TB_CustomControlsSwift/BWCircularSlider.swift +++ b/TB_CustomControlsSwift/BWCircularSlider.swift @@ -10,7 +10,7 @@ import UIKit struct Config { - static let TB_SLIDER_SIZE:CGFloat = UIScreen.mainScreen().bounds.size.width + static let TB_SLIDER_SIZE:CGFloat = UIScreen.main.bounds.size.width static let TB_SAFEAREA_PADDING:CGFloat = 60.0 static let TB_LINE_WIDTH:CGFloat = 40.0 static let TB_FONTSIZE:CGFloat = 40.0 @@ -20,15 +20,15 @@ struct Config { // MARK: Math Helpers -func DegreesToRadians (value:Double) -> Double { +func DegreesToRadians (_ value:Double) -> Double { return value * M_PI / 180.0 } -func RadiansToDegrees (value:Double) -> Double { +func RadiansToDegrees (_ value:Double) -> Double { return value * 180.0 / M_PI } -func Square (value:CGFloat) -> CGFloat { +func Square (_ value:CGFloat) -> CGFloat { return value * value } @@ -40,8 +40,8 @@ class BWCircularSlider: UIControl { var textField:UITextField? var radius:CGFloat = 0 var angle:Int = 360 - var startColor = UIColor.blueColor() - var endColor = UIColor.purpleColor() + var startColor = UIColor.blue + var endColor = UIColor.purple // Custom initializer convenience init(startColor:UIColor, endColor:UIColor, frame:CGRect){ @@ -55,8 +55,8 @@ class BWCircularSlider: UIControl { override init(frame: CGRect) { super.init(frame: frame) - self.backgroundColor = UIColor.clearColor() - self.opaque = true + self.backgroundColor = UIColor.clear + self.isOpaque = true //Define the circle radius taking into account the safe area radius = self.frame.size.width/2 - Config.TB_SAFEAREA_PADDING @@ -65,18 +65,18 @@ class BWCircularSlider: UIControl { let font = UIFont(name: "Avenir", size: Config.TB_FONTSIZE) //Calculate font size needed to display 3 numbers let str = "000" as NSString - let fontSize:CGSize = str.sizeWithAttributes([NSFontAttributeName:font!]) + let fontSize:CGSize = str.size(attributes: [NSFontAttributeName:font!]) //Using a TextField area we can easily modify the control to get user input from this field - let textFieldRect = CGRectMake( - (frame.size.width - fontSize.width) / 2.0, - (frame.size.height - fontSize.height) / 2.0, - fontSize.width, fontSize.height); + let textFieldRect = CGRect( + x: (frame.size.width - fontSize.width) / 2.0, + y: (frame.size.height - fontSize.height) / 2.0, + width: fontSize.width, height: fontSize.height); textField = UITextField(frame: textFieldRect) - textField?.backgroundColor = UIColor.clearColor() + textField?.backgroundColor = UIColor.clear textField?.textColor = UIColor(white: 1.0, alpha: 0.8) - textField?.textAlignment = .Center + textField?.textAlignment = .center textField?.font = font textField?.text = "\(self.angle)" @@ -88,35 +88,35 @@ class BWCircularSlider: UIControl { } - override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool { - super.beginTrackingWithTouch(touch, withEvent: event) + override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { + super.beginTracking(touch, with: event) return true } - override func continueTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) -> Bool { - super.continueTrackingWithTouch(touch, withEvent: event) + override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { + super.continueTracking(touch, with: event) - let lastPoint = touch.locationInView(self) + let lastPoint = touch.location(in: self) self.moveHandle(lastPoint) - self.sendActionsForControlEvents(UIControlEvents.ValueChanged) + self.sendActions(for: UIControlEvents.valueChanged) return true } - override func endTrackingWithTouch(touch: UITouch, withEvent event: UIEvent) { - super.endTrackingWithTouch(touch, withEvent: event) + override func endTracking(_ touch: UITouch?, with event: UIEvent?) { + super.endTracking(touch, with: event) } //Use the draw rect to draw the Background, the Circle and the Handle - override func drawRect(rect: CGRect){ - super.drawRect(rect) + override func draw(_ rect: CGRect){ + super.draw(rect) let ctx = UIGraphicsGetCurrentContext() @@ -126,42 +126,42 @@ class BWCircularSlider: UIControl { CGContextAddArc(ctx, CGFloat(self.frame.size.width / 2.0), CGFloat(self.frame.size.height / 2.0), radius, 0, CGFloat(M_PI * 2), 0) UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0).set() - CGContextSetLineWidth(ctx, 72) - CGContextSetLineCap(ctx, kCGLineCapButt) + ctx?.setLineWidth(72) + ctx?.setLineCap(kCALineCapButt) - CGContextDrawPath(ctx, kCGPathStroke) + ctx.drawPath(using: kCGPathStroke) /** Draw the circle **/ /** Create THE MASK Image **/ - UIGraphicsBeginImageContext(CGSizeMake(self.bounds.size.width,self.bounds.size.height)); + UIGraphicsBeginImageContext(CGSize(width: self.bounds.size.width,height: self.bounds.size.height)); let imageCtx = UIGraphicsGetCurrentContext() CGContextAddArc(imageCtx, CGFloat(self.frame.size.width/2) , CGFloat(self.frame.size.height/2), radius, 0, CGFloat(DegreesToRadians(Double(angle))) , 0); - UIColor.redColor().set() + UIColor.red.set() //Use shadow to create the Blur effect - CGContextSetShadowWithColor(imageCtx, CGSizeMake(0, 0), CGFloat(self.angle/15), UIColor.blackColor().CGColor); + imageCtx?.setShadow(offset: CGSize(width: 0, height: 0), blur: CGFloat(self.angle/15), color: UIColor.black.cgColor); //define the path - CGContextSetLineWidth(imageCtx, Config.TB_LINE_WIDTH) - CGContextDrawPath(imageCtx, kCGPathStroke) + imageCtx?.setLineWidth(Config.TB_LINE_WIDTH) + imageCtx.drawPath(using: kCGPathStroke) //save the context content into the image mask - var mask:CGImageRef = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext()); + var mask:CGImage = UIGraphicsGetCurrentContext()!.makeImage()!; UIGraphicsEndImageContext(); /** Clip Context to the mask **/ - CGContextSaveGState(ctx) + ctx?.saveGState() - CGContextClipToMask(ctx, self.bounds, mask) + ctx?.clip(to: self.bounds, mask: mask) /** The Gradient **/ // Split colors in components (rgba) - let startColorComps:UnsafePointer = CGColorGetComponents(startColor.CGColor); - let endColorComps:UnsafePointer = CGColorGetComponents(endColor.CGColor); + let startColorComps:UnsafePointer = startColor.cgColor.components; + let endColorComps:UnsafePointer = endColor.cgColor.components; let components : [CGFloat] = [ startColorComps[0], startColorComps[1], startColorComps[2], 1.0, // Start color @@ -170,18 +170,18 @@ class BWCircularSlider: UIControl { // Setup the gradient let baseSpace = CGColorSpaceCreateDeviceRGB() - let gradient = CGGradientCreateWithColorComponents(baseSpace, components, nil, 2) + let gradient = CGGradient(colorSpace: baseSpace, colorComponents: components, locations: nil, count: 2) // Gradient direction - let startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)) - let endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)) + let startPoint = CGPoint(x: rect.midX, y: rect.minY) + let endPoint = CGPoint(x: rect.midX, y: rect.maxY) // Draw the gradient - CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, 0); - CGContextRestoreGState(ctx); + ctx?.drawLinearGradient(gradient!, start: startPoint, end: endPoint, options: CGGradientDrawingOptions(rawValue: 0)); + ctx?.restoreGState(); /* Draw the handle */ - drawTheHandle(ctx) + drawTheHandle(ctx!) } @@ -189,31 +189,31 @@ class BWCircularSlider: UIControl { /** Draw a white knob over the circle **/ - func drawTheHandle(ctx:CGContextRef){ + func drawTheHandle(_ ctx:CGContext){ - CGContextSaveGState(ctx); + ctx.saveGState(); //I Love shadows - CGContextSetShadowWithColor(ctx, CGSizeMake(0, 0), 3, UIColor.blackColor().CGColor); + ctx.setShadow(offset: CGSize(width: 0, height: 0), blur: 3, color: UIColor.black.cgColor); //Get the handle position - var handleCenter = pointFromAngle(angle) + let handleCenter = pointFromAngle(angle) //Draw It! UIColor(white:1.0, alpha:0.7).set(); - CGContextFillEllipseInRect(ctx, CGRectMake(handleCenter.x, handleCenter.y, Config.TB_LINE_WIDTH, Config.TB_LINE_WIDTH)); + ctx.fillEllipse(in: CGRect(x: handleCenter.x, y: handleCenter.y, width: Config.TB_LINE_WIDTH, height: Config.TB_LINE_WIDTH)); - CGContextRestoreGState(ctx); + ctx.restoreGState(); } /** Move the Handle **/ - func moveHandle(lastPoint:CGPoint){ + func moveHandle(_ lastPoint:CGPoint){ //Get the center - let centerPoint:CGPoint = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); + let centerPoint:CGPoint = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2); //Calculate the direction from a center point and a arbitrary position. let currentAngle:Double = AngleFromNorth(centerPoint, p2: lastPoint, flipped: false); let angleInt = Int(floor(currentAngle)) @@ -229,13 +229,13 @@ class BWCircularSlider: UIControl { } /** Given the angle, get the point position on circumference **/ - func pointFromAngle(angleInt:Int)->CGPoint{ + func pointFromAngle(_ angleInt:Int)->CGPoint{ //Circle center - let centerPoint = CGPointMake(self.frame.size.width/2.0 - Config.TB_LINE_WIDTH/2.0, self.frame.size.height/2.0 - Config.TB_LINE_WIDTH/2.0); + let centerPoint = CGPoint(x: self.frame.size.width/2.0 - Config.TB_LINE_WIDTH/2.0, y: self.frame.size.height/2.0 - Config.TB_LINE_WIDTH/2.0); //The point position on the circumference - var result:CGPoint = CGPointZero + var result:CGPoint = CGPoint.zero let y = round(Double(radius) * sin(DegreesToRadians(Double(-angleInt)))) + Double(centerPoint.y) let x = round(Double(radius) * cos(DegreesToRadians(Double(-angleInt)))) + Double(centerPoint.x) result.y = CGFloat(y) @@ -247,8 +247,8 @@ class BWCircularSlider: UIControl { //Sourcecode from Apple example clockControl //Calculate the direction in degrees from a center point to an arbitrary position. - func AngleFromNorth(p1:CGPoint , p2:CGPoint , flipped:Bool) -> Double { - var v:CGPoint = CGPointMake(p2.x - p1.x, p2.y - p1.y) + func AngleFromNorth(_ p1:CGPoint , p2:CGPoint , flipped:Bool) -> Double { + var v:CGPoint = CGPoint(x: p2.x - p1.x, y: p2.y - p1.y) let vmag:CGFloat = Square(Square(v.x) + Square(v.y)) var result:Double = 0.0 v.x /= vmag; diff --git a/TB_CustomControlsSwift/BWCircularSliderView.swift b/TB_CustomControlsSwift/BWCircularSliderView.swift index ccfcf53..6a2876e 100644 --- a/TB_CustomControlsSwift/BWCircularSliderView.swift +++ b/TB_CustomControlsSwift/BWCircularSliderView.swift @@ -10,8 +10,8 @@ import UIKit @IBDesignable class BWCircularSliderView: UIView { - @IBInspectable var startColor:UIColor = UIColor.redColor() - @IBInspectable var endColor:UIColor = UIColor.blueColor() + @IBInspectable var startColor:UIColor = UIColor.red + @IBInspectable var endColor:UIColor = UIColor.blue #if TARGET_INTERFACE_BUILDER override func willMoveToSuperview(newSuperview: UIView?) { @@ -30,7 +30,7 @@ import UIKit let slider:BWCircularSlider = BWCircularSlider(startColor:self.startColor, endColor:self.endColor, frame: self.bounds) // Attach an Action and a Target to the slider - slider.addTarget(self, action: "valueChanged:", forControlEvents: UIControlEvents.ValueChanged) + slider.addTarget(self, action: #selector(BWCircularSliderView.valueChanged(_:)), for: UIControlEvents.valueChanged) // Add the slider as subview of this view self.addSubview(slider) @@ -38,8 +38,8 @@ import UIKit } #endif - func valueChanged(slider:BWCircularSlider){ + func valueChanged(_ slider:BWCircularSlider){ // Do something with the value... - println("Value changed \(slider.angle)") + print("Value changed \(slider.angle)") } } From d9f330092f29be2e1cba1d8ea405a434a38b2574 Mon Sep 17 00:00:00 2001 From: Mitchell Hudson Date: Sun, 15 Jan 2017 19:58:37 -0800 Subject: [PATCH 2/2] Alan I made a pull request! --- .../UserInterfaceState.xcuserstate | Bin 11075 -> 13110 bytes TB_CustomControlsSwift/BWCircularSlider.swift | 102 +++++++++++------- .../Base.lproj/Main.storyboard | 21 ++-- 3 files changed, 74 insertions(+), 49 deletions(-) diff --git a/BWCircularSlider.xcodeproj/project.xcworkspace/xcuserdata/mitchellhudson.xcuserdatad/UserInterfaceState.xcuserstate b/BWCircularSlider.xcodeproj/project.xcworkspace/xcuserdata/mitchellhudson.xcuserdatad/UserInterfaceState.xcuserstate index 59bf57858a2587d70fa8078f1a49cd011f6a67d4..8ab7088ced9a7258bb7cb9829fc01363c1202278 100644 GIT binary patch delta 7973 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 delta 6146 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 AX#fBK diff --git a/TB_CustomControlsSwift/BWCircularSlider.swift b/TB_CustomControlsSwift/BWCircularSlider.swift index b74afe7..04afb14 100644 --- a/TB_CustomControlsSwift/BWCircularSlider.swift +++ b/TB_CustomControlsSwift/BWCircularSlider.swift @@ -9,12 +9,10 @@ import UIKit struct Config { - static let TB_SLIDER_SIZE:CGFloat = UIScreen.main.bounds.size.width static let TB_SAFEAREA_PADDING:CGFloat = 60.0 static let TB_LINE_WIDTH:CGFloat = 40.0 static let TB_FONTSIZE:CGFloat = 40.0 - } @@ -37,7 +35,7 @@ func Square (_ value:CGFloat) -> CGFloat { class BWCircularSlider: UIControl { - var textField:UITextField? + var textField:UITextField = UITextField() var radius:CGFloat = 0 var angle:Int = 360 var startColor = UIColor.blue @@ -59,7 +57,7 @@ class BWCircularSlider: UIControl { self.isOpaque = true //Define the circle radius taking into account the safe area - radius = self.frame.size.width/2 - Config.TB_SAFEAREA_PADDING + radius = self.frame.size.width / 2 - Config.TB_SAFEAREA_PADDING //Define the Font let font = UIFont(name: "Avenir", size: Config.TB_FONTSIZE) @@ -73,14 +71,14 @@ class BWCircularSlider: UIControl { y: (frame.size.height - fontSize.height) / 2.0, width: fontSize.width, height: fontSize.height); - textField = UITextField(frame: textFieldRect) - textField?.backgroundColor = UIColor.clear - textField?.textColor = UIColor(white: 1.0, alpha: 0.8) - textField?.textAlignment = .center - textField?.font = font - textField?.text = "\(self.angle)" + textField.frame = textFieldRect + textField.backgroundColor = UIColor.clear + textField.textColor = UIColor(white: 1.0, alpha: 0.8) + textField.textAlignment = .center + textField.font = font + textField.text = "\(self.angle)" - addSubview(textField!) + addSubview(textField) } required init(coder aDecoder: NSCoder) { @@ -99,9 +97,7 @@ class BWCircularSlider: UIControl { super.continueTracking(touch, with: event) let lastPoint = touch.location(in: self) - self.moveHandle(lastPoint) - self.sendActions(for: UIControlEvents.valueChanged) return true @@ -118,70 +114,94 @@ class BWCircularSlider: UIControl { override func draw(_ rect: CGRect){ super.draw(rect) - let ctx = UIGraphicsGetCurrentContext() - + guard let ctx = UIGraphicsGetCurrentContext() else { + print(#function, "Couldn't get context") + return + } /** Draw the Background **/ - CGContextAddArc(ctx, CGFloat(self.frame.size.width / 2.0), CGFloat(self.frame.size.height / 2.0), radius, 0, CGFloat(M_PI * 2), 0) - UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0).set() - - ctx?.setLineWidth(72) - ctx?.setLineCap(kCALineCapButt) + let center = CGPoint(x: bounds.midX, y: bounds.midY) + let pi2 = CGFloat(M_PI * 2) + ctx.addArc(center: center, radius: radius, startAngle: 0, endAngle: pi2, clockwise: false) - ctx.drawPath(using: kCGPathStroke) + UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0).set() + ctx.setLineWidth(Config.TB_LINE_WIDTH * 2) + ctx.setLineCap(.butt) + ctx.drawPath(using: .stroke) /** Draw the circle **/ /** Create THE MASK Image **/ - UIGraphicsBeginImageContext(CGSize(width: self.bounds.size.width,height: self.bounds.size.height)); - let imageCtx = UIGraphicsGetCurrentContext() - CGContextAddArc(imageCtx, CGFloat(self.frame.size.width/2) , CGFloat(self.frame.size.height/2), radius, 0, CGFloat(DegreesToRadians(Double(angle))) , 0); - UIColor.red.set() + + // FIXME: ??? + UIGraphicsBeginImageContext(CGSize(width: self.bounds.size.width, height: self.bounds.size.height)); + + guard let imageCtx = UIGraphicsGetCurrentContext() else { + print(#function, #line, "Couldn't get image context") + return + } + + let endAngle = CGFloat(DegreesToRadians(Double(angle))) + imageCtx.addArc(center: center, radius: radius, startAngle: 0, endAngle: endAngle, clockwise: false) + + UIColor.yellow.set() //Use shadow to create the Blur effect - imageCtx?.setShadow(offset: CGSize(width: 0, height: 0), blur: CGFloat(self.angle/15), color: UIColor.black.cgColor); + imageCtx.setShadow(offset: CGSize(width: 0, height: 0), blur: CGFloat(self.angle/15), color: UIColor.black.cgColor); //define the path - imageCtx?.setLineWidth(Config.TB_LINE_WIDTH) - imageCtx.drawPath(using: kCGPathStroke) + imageCtx.setLineWidth(Config.TB_LINE_WIDTH) + imageCtx.setLineCap(.round) + imageCtx.drawPath(using: .stroke) - //save the context content into the image mask - var mask:CGImage = UIGraphicsGetCurrentContext()!.makeImage()!; + // save the context content into the image mask + let mask:CGImage = UIGraphicsGetCurrentContext()!.makeImage()!; UIGraphicsEndImageContext(); /** Clip Context to the mask **/ - ctx?.saveGState() + ctx.saveGState() - ctx?.clip(to: self.bounds, mask: mask) + ctx.clip(to: self.bounds, mask: mask) /** The Gradient **/ // Split colors in components (rgba) - let startColorComps:UnsafePointer = startColor.cgColor.components; - let endColorComps:UnsafePointer = endColor.cgColor.components; + guard let startColorComps = startColor.cgColor.components else { + print(#function, #line, "Couldn't get start color components") + return + } + + + guard let endColorComps = endColor.cgColor.components else { + print(#function, #line, "Couldn't get end color components") + return + } let components : [CGFloat] = [ - startColorComps[0], startColorComps[1], startColorComps[2], 1.0, // Start color - endColorComps[0], endColorComps[1], endColorComps[2], 1.0 // End color + startColorComps[0], startColorComps[1], startColorComps[2], 1.0, // Start color + endColorComps[0], endColorComps[1], endColorComps[2], 1.0 // End color ] // Setup the gradient let baseSpace = CGColorSpaceCreateDeviceRGB() - let gradient = CGGradient(colorSpace: baseSpace, colorComponents: components, locations: nil, count: 2) + guard let gradient = CGGradient(colorSpace: baseSpace, colorComponents: components, locations: nil, count: 2) else { + print(#function, #line, "Couldn't make gradient?") + return + } // Gradient direction let startPoint = CGPoint(x: rect.midX, y: rect.minY) let endPoint = CGPoint(x: rect.midX, y: rect.maxY) // Draw the gradient - ctx?.drawLinearGradient(gradient!, start: startPoint, end: endPoint, options: CGGradientDrawingOptions(rawValue: 0)); - ctx?.restoreGState(); + ctx.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: CGGradientDrawingOptions(rawValue: 0)); + ctx.restoreGState(); /* Draw the handle */ - drawTheHandle(ctx!) + drawTheHandle(ctx) } @@ -222,7 +242,7 @@ class BWCircularSlider: UIControl { angle = Int(360 - angleInt) //Update the textfield - textField!.text = "\(angle)" + textField.text = "\(angle)" //Redraw setNeedsDisplay() diff --git a/TB_CustomControlsSwift/Base.lproj/Main.storyboard b/TB_CustomControlsSwift/Base.lproj/Main.storyboard index 04cd409..bc12565 100644 --- a/TB_CustomControlsSwift/Base.lproj/Main.storyboard +++ b/TB_CustomControlsSwift/Base.lproj/Main.storyboard @@ -1,7 +1,12 @@ - - + + + + + - + + + @@ -13,26 +18,26 @@ - + - + - + - + - +