Skip to content

Update to XCode 8 / Swift 3 #6

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

Open
wants to merge 1 commit 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
3 changes: 3 additions & 0 deletions BWCircularSlider.xcodeproj/project.pbxproj
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
TargetAttributes = {
DAEB2FAD1A0827EE002EE5EF = {
CreatedOnToolsVersion = 6.0.1;
LastSwiftMigration = 0820;
};
};
};
Expand Down Expand Up @@ -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;
};
Expand All @@ -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;
};
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
12 changes: 6 additions & 6 deletions TB_CustomControlsSwift/AppDelegate.swift
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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:.
}

Expand Down
145 changes: 73 additions & 72 deletions TB_CustomControlsSwift/BWCircularSlider.swift
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,35 @@
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
}


// MARK: Circular Slider

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){
Expand All @@ -55,8 +51,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
Expand All @@ -65,18 +61,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)"

Expand All @@ -88,80 +84,86 @@ 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()


/** 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)
let point = CGPoint(x: CGFloat(self.frame.size.width / 2.0), y: CGFloat(self.frame.size.height / 2.0))

ctx?.addArc(center: point, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI * 2), clockwise: false)

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(.butt)

CGContextDrawPath(ctx, kCGPathStroke)
ctx?.drawPath(using: .stroke)


/** 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()
imageCtx?.addArc(center: point, radius: radius, startAngle: 0, endAngle: CGFloat(DegreesToRadians(Double(angle))), clockwise: false)

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: .stroke)

//save the context content into the image mask
var mask:CGImageRef = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
UIGraphicsEndImageContext();
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<CGFloat> = CGColorGetComponents(startColor.CGColor);
let endColorComps:UnsafePointer<CGFloat> = CGColorGetComponents(endColor.CGColor);

let startColorComps = startColor.cgColor.components!
let endColorComps = endColor.cgColor.components!

let components : [CGFloat] = [
startColorComps[0], startColorComps[1], startColorComps[2], 1.0, // Start color
Expand All @@ -170,52 +172,51 @@ 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!)

}



/** 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));
UIColor(white:1.0, alpha:0.7).set()
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 currentAngle:Double = AngleFromNorth(centerPoint, p2: lastPoint, flipped: false)
let angleInt = Int(floor(currentAngle))

//Store the new angle
Expand All @@ -229,33 +230,33 @@ 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)
result.x = CGFloat(x)

return result;
return result
}


//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;
v.y /= vmag;
v.x /= vmag
v.y /= vmag
let radians = Double(atan2(v.y,v.x))
result = RadiansToDegrees(radians)
return (result >= 0 ? result : result + 360.0);
return (result >= 0 ? result : result + 360.0)
}

}
Loading