I've translated Leo library's in Swift 3.x , in other words , the good WCGradientCircleLayer writed in objective-C (it work exactly as aspected)
import UIKit
class WCGraintCircleLayer: CALayer {
override init () {
super.init()
}
convenience init(bounds:CGRect,position:CGPoint,fromColor:UIColor,toColor:UIColor,linewidth:CGFloat,toValue:CGFloat) {
self.init()
self.bounds = bounds
self.position = position
let colors : [UIColor] = self.graint(fromColor: fromColor, toColor:toColor, count:4)
for i in 0..<colors.count-1 {
let graint = CAGradientLayer()
graint.bounds = CGRect(origin:CGPoint.zero, size: CGSize(width:bounds.width/2,height:bounds.height/2))
let valuePoint = self.positionArrayWith(bounds: self.bounds)[i]
graint.position = valuePoint
print("iesimo graint position: (graint.position)")
let fromColor = colors[i]
let toColor = colors[i+1]
let colors : [CGColor] = [fromColor.cgColor,toColor.cgColor]
let stopOne: CGFloat = 0.0
let stopTwo: CGFloat = 1.0
let locations : [CGFloat] = [stopOne,stopTwo]
graint.colors = colors
graint.locations = locations as [NSNumber]? // with Swift 2 and Swift 3 you can cast directly a `CGFloat` value to `NSNumber` and back
graint.startPoint = self.startPoints()[i]
graint.endPoint = self.endPoints()[i]
self.addSublayer(graint)
//Set mask
let shapelayer = CAShapeLayer()
let rect = CGRect(origin:CGPoint.zero,size:CGSize(width:self.bounds.width - 2 * linewidth,height: self.bounds.height - 2 * linewidth))
shapelayer.bounds = rect
shapelayer.position = CGPoint(x:self.bounds.width/2,y: self.bounds.height/2)
shapelayer.strokeColor = UIColor.blue.cgColor
shapelayer.fillColor = UIColor.clear.cgColor
shapelayer.path = UIBezierPath(roundedRect: rect, cornerRadius: rect.width/2).cgPath
shapelayer.lineWidth = linewidth
shapelayer.lineCap = kCALineCapRound
shapelayer.strokeStart = 0.010
let finalValue = (toValue*0.99)
shapelayer.strokeEnd = finalValue//0.99;
self.mask = shapelayer
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func layerWithWithBounds(bounds:CGRect, position:CGPoint, fromColor:UIColor, toColor:UIColor, linewidth : CGFloat,toValue:CGFloat) -> WCGraintCircleLayer {
let layer = WCGraintCircleLayer(bounds: bounds,position: position,fromColor:fromColor, toColor: toColor,linewidth: linewidth,toValue:toValue )
return layer
}
func graint(fromColor:UIColor, toColor:UIColor, count:Int) -> [UIColor]{
var fromR:CGFloat = 0.0,fromG:CGFloat = 0.0,fromB:CGFloat = 0.0,fromAlpha:CGFloat = 0.0
fromColor.getRed(&fromR,green: &fromG,blue: &fromB,alpha: &fromAlpha)
var toR:CGFloat = 0.0,toG:CGFloat = 0.0,toB:CGFloat = 0.0,toAlpha:CGFloat = 0.0
toColor.getRed(&toR,green: &toG,blue: &toB,alpha: &toAlpha)
var result : [UIColor]! = [UIColor]()
for i in 0...count {
let oneR:CGFloat = fromR + (toR - fromR)/CGFloat(count) * CGFloat(i)
let oneG : CGFloat = fromG + (toG - fromG)/CGFloat(count) * CGFloat(i)
let oneB : CGFloat = fromB + (toB - fromB)/CGFloat(count) * CGFloat(i)
let oneAlpha : CGFloat = fromAlpha + (toAlpha - fromAlpha)/CGFloat(count) * CGFloat(i)
let oneColor = UIColor.init(red: oneR, green: oneG, blue: oneB, alpha: oneAlpha)
result.append(oneColor)
print(oneColor)
}
return result
}
func positionArrayWith(bounds:CGRect) -> [CGPoint]{
let first = CGPoint(x:(bounds.width/4)*3,y: (bounds.height/4)*1)
let second = CGPoint(x:(bounds.width/4)*3,y: (bounds.height/4)*3)
let third = CGPoint(x:(bounds.width/4)*1,y: (bounds.height/4)*3)
let fourth = CGPoint(x:(bounds.width/4)*1,y: (bounds.height/4)*1)
print([first,second,third,fourth])
return [first,second,third,fourth]
}
func startPoints() -> [CGPoint] {
return [CGPoint.zero,CGPoint(x:1,y:0),CGPoint(x:1,y:1),CGPoint(x:0,y:1)]
}
func endPoints() -> [CGPoint] {
return [CGPoint(x:1,y:1),CGPoint(x:0,y:1),CGPoint.zero,CGPoint(x:1,y:0)]
}
func midColorWithFromColor(fromColor:UIColor, toColor:UIColor, progress:CGFloat) -> UIColor {
var fromR:CGFloat = 0.0,fromG:CGFloat = 0.0,fromB:CGFloat = 0.0,fromAlpha:CGFloat = 0.0
fromColor.getRed(&fromR,green: &fromG,blue: &fromB,alpha: &fromAlpha)
var toR:CGFloat = 0.0,toG:CGFloat = 0.0,toB:CGFloat = 0.0,toAlpha:CGFloat = 0.0
toColor.getRed(&toR,green: &toG,blue: &toB,alpha: &toAlpha)
let oneR = fromR + (toR - fromR) * progress
let oneG = fromG + (toG - fromG) * progress
let oneB = fromB + (toB - fromB) * progress
let oneAlpha = fromAlpha + (toAlpha - fromAlpha) * progress
let oneColor = UIColor.init(red: oneR, green: oneG, blue: oneB, alpha: oneAlpha)
return oneColor
}
// This is what you call if you want to draw a full circle.
func animateCircle(duration: TimeInterval) {
animateCircleTo(duration: duration, fromValue: 0.010, toValue: 0.99)
}
// This is what you call to draw a partial circle.
func animateCircleTo(duration: TimeInterval, fromValue: CGFloat, toValue: CGFloat){
// We want to animate the strokeEnd property of the circleLayer
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.isRemovedOnCompletion = true
// Set the animation duration appropriately
animation.duration = duration
// Animate from 0.010 (no circle) to 0.99 (full circle)
animation.fromValue = 0.010
animation.toValue = toValue
// Do an easeout. Don't know how to do a spring instead
//animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
// Set the circleLayer's strokeEnd property to 0.99 now so that it's the
// right value when the animation ends.
let circleMask = self.mask as! CAShapeLayer
circleMask.strokeEnd = toValue
// Do the actual animation
circleMask.removeAllAnimations()
circleMask.add(animation, forKey: "animateCircle")
}
}
And this is a little example, how to use in Swift 3.x:
let gradientRingLayer = WCGraintCircleLayer(bounds: CGRect(origin: CGPoint.zero,size:CGSize(width: 150, height: 150)), position:CGPoint(x: 200, y: 300),fromColor:UIColor.blue, toColor:UIColor.white, linewidth:4.0, toValue:0)
self.view.layer.addSublayer(gradientRingLayer)
let duration = 3.0
gradientRingLayer.animateCircleTo(duration: duration, fromValue: 0, toValue: 0.99)
This is the code in Swift 2.x:
import UIKit
class WCGraintCircleLayer: CALayer {
override init () {
super.init()
}
convenience init(bounds:CGRect,position:CGPoint,fromColor:UIColor,toColor:UIColor,linewidth:CGFloat,toValue:CGFloat) {
self.init()
self.bounds = bounds
self.position = position
let colors : [UIColor] = self.graintFromColor(fromColor, toColor:toColor, count:4)
for i in 0..<colors.count-1 {
let graint = CAGradientLayer()
graint.bounds = CGRectMake(0,0,CGRectGetWidth(bounds)/2,CGRectGetHeight(bounds)/2)
let valuePoint = self.positionArrayWithMainBounds(self.bounds)[i]
graint.position = valuePoint
print("iesimo graint position: (graint.position)")
let fromColor = colors[i]
let toColor = colors[i+1]
let colors : [CGColorRef] = [fromColor.CGColor,toColor.CGColor]
let stopOne: CGFloat = 0.0
let stopTwo: CGFloat = 1.0
let locations : [CGFloat] = [stopOne,stopTwo]
graint.colors = colors
graint.locations = locations
graint.startPoint = self.startPoints()[i]
graint.endPoint = self.endPoints()[i]
self.addSublayer(graint)
//Set mask
let shapelayer = CAShapeLayer()
let rect = CGRectMake(0,0,CGRectGetWidth(self.bounds) - 2 * linewidth, CGRectGetHeight(self.bounds) - 2 * linewidth)
shapelayer.bounds = rect
shapelayer.position = CGPointMake(CGRectGetWidth(self.bounds)/2, CGRectGetHeight(self.bounds)/2)
shapelayer.strokeColor = UIColor.blueColor().CGColor
shapelayer.fillColor = UIColor.clearColor().CGColor
shapelayer.path = UIBezierPath(roundedRect: rect, cornerRadius: CGRectGetWidth(rect)/2).CGPath
shapelayer.lineWidth = linewidth
shapelayer.lineCap = kCALineCapRound
shapelayer.strokeStart = 0.010
let finalValue = (toValue*0.99)
shapelayer.strokeEnd = finalValue//0.99;
self.mask = shapelayer
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func layerWithWithBounds(bounds:CGRect, position:CGPoint, fromColor:UIColor, toColor:UIColor, linewidth : CGFloat,toValue:CGFloat) -> WCGraintCircleLayer {
let layer = WCGraintCircleLayer(bounds: bounds,position: position,fromColor:fromColor, toColor: toColor,linewidth: linewidth,toValue:toValue )
return layer
}
func graintFromColor(fromColor:UIColor, toColor:UIColor, count:Int) -> [UIColor]{
var fromR:CGFloat = 0.0,fromG:CGFloat = 0.0,fromB:CGFloat = 0.0,fromAlpha:CGFloat = 0.0
fromColor.getRed(&fromR,green: &fromG,blue: &fromB,alpha: &fromAlpha)
var toR:CGFloat = 0.0,toG:CGFloat = 0.0,toB:CGFloat = 0.0,toAlpha:CGFloat = 0.0
toColor.getRed(&toR,green: &toG,blue: &toB,alpha: &toAlpha)
var result : [UIColor]! = [UIColor]()
for i in 0...count {
let oneR:CGFloat = fromR + (toR - fromR)/CGFloat(count) * CGFloat(i)
let oneG : CGFloat = fromG + (toG - fromG)/CGFloat(count) * CGFloat(i)
let oneB : CGFloat = fromB + (toB - fromB)/CGFloat(count) * CGFloat(i)
let oneAlpha : CGFloat = fromAlpha + (toAlpha - fromAlpha)/CGFloat(count) * CGFloat(i)
let oneColor = UIColor.init(red: oneR, green: oneG, blue: oneB, alpha: oneAlpha)
result.append(oneColor)
print(oneColor)
}
return result
}
func positionArrayWithMainBounds(bounds:CGRect) -> [CGPoint]{
let first = CGPointMake((CGRectGetWidth(bounds)/4)*3, (CGRectGetHeight(bounds)/4)*1)
let second = CGPointMake((CGRectGetWidth(bounds)/4)*3, (CGRectGetHeight(bounds)/4)*3)
let third = CGPointMake((CGRectGetWidth(bounds)/4)*1, (CGRectGetHeight(bounds)/4)*3)
let fourth = CGPointMake((CGRectGetWidth(bounds)/4)*1, (CGRectGetHeight(bounds)/4)*1)
print([first,second,third,fourth])
return [first,second,third,fourth]
}
func startPoints() -> [CGPoint] {
return [CGPointMake(0,0),CGPointMake(1,0),CGPointMake(1,1),CGPointMake(0,1)]
}
func endPoints() -> [CGPoint] {
return [CGPointMake(1,1),CGPointMake(0,1),CGPointMake(0,0),CGPointMake(1,0)]
}
func midColorWithFromColor(fromColor:UIColor, toColor:UIColor, progress:CGFloat) -> UIColor {
var fromR:CGFloat = 0.0,fromG:CGFloat = 0.0,fromB:CGFloat = 0.0