Skip to content

Instantly share code, notes, and snippets.

@stonetip
Last active May 10, 2016 18:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stonetip/be654788d94d901960e00167c4781f6b to your computer and use it in GitHub Desktop.
Save stonetip/be654788d94d901960e00167c4781f6b to your computer and use it in GitHub Desktop.
donut builder with timer
import UIKit
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
// all angles need to be converted to radians
func Degrees2Radians(degrees: Double) -> CGFloat{
return CGFloat( degrees * M_PI / 180)
}
// set width and height that will be used by the view and layers
let width = 1000
let height = 1000
let lineWidthScaleFactor = 0.1875
// values that will be used to draw the arc
var lineWidth = Double(width) * lineWidthScaleFactor
var radius = Double(width) / 2
// tweak values if height is less than width
if(width >= height){
lineWidth = Double(height) * lineWidthScaleFactor
radius = Double(height) / 2
}
// make the arc fit and look pretty
radius -= lineWidth / 2
let bounds = CGRect(x: 0, y: 0, width: width, height: height)
let view = UIView(frame: bounds)
// provide a shape layer and set its path to the arc
let shapeLayer = CAShapeLayer()
shapeLayer.frame = bounds // need this for the rotation transform to work correctly
view.layer.addSublayer(shapeLayer)
// define a start and end angle for the test arc
var startAngle = Degrees2Radians(0)
var endAngle = Degrees2Radians(180)
// give the layer some properties
shapeLayer.backgroundColor = UIColor.yellowColor().CGColor
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.lineWidth = CGFloat(lineWidth)
// create the arc
shapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: width / 2, y: height / 2), radius: CGFloat(radius), startAngle: startAngle, endAngle: endAngle, clockwise: true).CGPath
// Test using a different angle to see if if the donut redraws completely
endAngle = Degrees2Radians(45)
shapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: width / 2, y: height / 2), radius: CGFloat(radius), startAngle: startAngle, endAngle: endAngle, clockwise: true).CGPath
// this gives us a handy way to see the final results
view.backgroundColor = UIColor.purpleColor()
var testAngle: Double = 0
func drawDonut(){
print("incrementing...")
testAngle += 6
endAngle = Degrees2Radians(testAngle)
print(testAngle)
shapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: width / 2, y: height / 2), radius: CGFloat(radius), startAngle: startAngle, endAngle: endAngle, clockwise: true).CGPath
// this gives us a handy way to see the final results
view.backgroundColor = UIColor.lightGrayColor()
}
// Extend NSTimeInterval to provide the conversion functions.
extension NSTimeInterval {
var nSecMultiplier: Double {
return Double(NSEC_PER_SEC)
}
public func nSecs() -> Int64 {
return Int64(self * nSecMultiplier)
}
public func nSecs() -> UInt64 {
return UInt64(self * nSecMultiplier)
}
public func dispatchTime() -> dispatch_time_t {
// Since the last parameter takes an Int64, the version that returns an Int64 is used.
return dispatch_time(DISPATCH_TIME_NOW, self.nSecs())
}
}
// Define a simple function for getting a timer dispatch source.
func repeatingTimerWithInterval(interval: NSTimeInterval, leeway: NSTimeInterval, action: dispatch_block_t) -> dispatch_source_t {
let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue())
guard timer != nil else { fatalError() }
dispatch_source_set_event_handler(timer, action)
// This function takes the UInt64 for the last two parameters
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, interval.nSecs(), leeway.nSecs())
dispatch_resume(timer)
return timer
}
// The interval that we will use
let interval: NSTimeInterval = 0.01 // 1.0 and 0.1 work fine, 0.01 does not
// Create the timer
let timer = repeatingTimerWithInterval(interval, leeway: 0.0) { () -> Void in
drawDonut()
}
// Turn off the timer after a few seconds
dispatch_after((interval * 60).dispatchTime(), dispatch_get_main_queue()) { () -> Void in
dispatch_source_cancel(timer)
XCPlaygroundPage.currentPage.finishExecution()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment