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 0000000..8ab7088
Binary files /dev/null and b/BWCircularSlider.xcodeproj/project.xcworkspace/xcuserdata/mitchellhudson.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/BWCircularSlider.xcodeproj/xcuserdata/mitchellhudson.xcuserdatad/xcschemes/BWCircularSlider.xcscheme b/BWCircularSlider.xcodeproj/xcuserdata/mitchellhudson.xcuserdatad/xcschemes/BWCircularSlider.xcscheme
new file mode 100644
index 0000000..e5c6ccb
--- /dev/null
+++ b/BWCircularSlider.xcodeproj/xcuserdata/mitchellhudson.xcuserdatad/xcschemes/BWCircularSlider.xcscheme
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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..04afb14 100644
--- a/TB_CustomControlsSwift/BWCircularSlider.swift
+++ b/TB_CustomControlsSwift/BWCircularSlider.swift
@@ -9,26 +9,24 @@
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
-
}
// 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
}
@@ -37,11 +35,11 @@ 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.blueColor()
- var endColor = UIColor.purpleColor()
+ var startColor = UIColor.blue
+ var endColor = UIColor.purple
// Custom initializer
convenience init(startColor:UIColor, endColor:UIColor, frame:CGRect){
@@ -55,32 +53,32 @@ 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
+ radius = self.frame.size.width / 2 - Config.TB_SAFEAREA_PADDING
//Define the Font
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);
-
- textField = UITextField(frame: textFieldRect)
- textField?.backgroundColor = UIColor.clearColor()
- textField?.textColor = UIColor(white: 1.0, alpha: 0.8)
- textField?.textAlignment = .Center
- textField?.font = font
- textField?.text = "\(self.angle)"
-
- addSubview(textField!)
+ 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.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)
}
required init(coder aDecoder: NSCoder) {
@@ -88,97 +86,119 @@ 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)
-
- let lastPoint = touch.locationInView(self)
+ override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
+ super.continueTracking(touch, with: event)
+ 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)
-
- let ctx = UIGraphicsGetCurrentContext()
+ override func draw(_ rect: CGRect){
+ super.draw(rect)
+ 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()
-
- CGContextSetLineWidth(ctx, 72)
- CGContextSetLineCap(ctx, kCGLineCapButt)
+ 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)
- CGContextDrawPath(ctx, 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(CGSizeMake(self.bounds.size.width,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()
+
+ // 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
- 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.setLineCap(.round)
+ imageCtx.drawPath(using: .stroke)
- //save the context content into the image mask
- var mask:CGImageRef = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
+ // save the context content into the image mask
+ let 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);
+ 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 = CGGradientCreateWithColorComponents(baseSpace, components, nil, 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 = 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)
@@ -189,31 +209,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))
@@ -222,20 +242,20 @@ class BWCircularSlider: UIControl {
angle = Int(360 - angleInt)
//Update the textfield
- textField!.text = "\(angle)"
+ textField.text = "\(angle)"
//Redraw
setNeedsDisplay()
}
/** 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 +267,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)")
}
}
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 @@
-
+
-
+
-
+
-
+
-
+