Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
Add support for custom knob paths, and knob images (#209)
Browse files Browse the repository at this point in the history
* add support for thumb image

* break up complex expression into multiple expressions

* support for custom knob paths

* version++

* add option to control drawing of the value knob

when current value equals minimum value

* version++

* add support for thumb image

* break up complex expression into multiple expressions

* support for custom knob paths

* add option to control drawing of the value knob

when current value equals minimum value

* remove trailing whitespace

* bump version to match upstream

* fix indentation

convert tabs to spaces
  • Loading branch information
wassup- authored and luispadron committed Sep 15, 2019
1 parent 9a81371 commit f54ef5f
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 65 deletions.
122 changes: 68 additions & 54 deletions src/UICircularProgressRing/UICircularRing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import UIKit

/**
# UICircularRing
This is the base class of `UICircularProgressRing` and `UICircularTimerRing`.
Expand All @@ -35,32 +35,32 @@ import UIKit
This is the UIView subclass that creates and handles everything
to do with the circular ring.
This class has a custom CAShapeLayer (`UICircularRingLayer`) which
handels the drawing and animating of the view
## Author
Luis Padron
*/
@IBDesignable open class UICircularRing: UIView {

// MARK: Circle Properties

/**
Whether or not the progress ring should be a full circle.
What this means is that the outer ring will always go from 0 - 360 degrees and
the inner ring will be calculated accordingly depending on current value.
## Important ##
Default = true
When this property is true any value set for `endAngle` will be ignored.
## Author
Luis Padron
*/
@IBInspectable open var fullCircle: Bool = true {
didSet { ringLayer.setNeedsDisplay() }
Expand All @@ -70,14 +70,14 @@ import UIKit

/**
The style of the progress ring.
Type: `UICircularRingStyle`
The five styles include `inside`, `ontop`, `dashed`, `dotted`, and `gradient`
## Important ##
Default = UICircularRingStyle.inside
## Author
Luis Padron
*/
Expand Down Expand Up @@ -111,6 +111,20 @@ import UIKit
didSet { ringLayer.setNeedsDisplay() }
}

/**
A toggle for showing or hiding the value knob when current value == minimum value.
If false the value knob will not be shown when current value == minimum value.
## Important ##
Default = false
## Author
Tom Knapen
*/
@IBInspectable public var shouldDrawMinValueKnob: Bool = false {
didSet { ringLayer.setNeedsDisplay() }
}

/**
Style for the value knob, default is `nil`.
Expand All @@ -124,15 +138,15 @@ import UIKit

/**
The start angle for the entire progress ring view.
Please note that Cocoa Touch uses a clockwise rotating unit circle.
I.e: 90 degrees is at the bottom and 270 degrees is at the top
## Important ##
Default = 0 (degrees)
Values should be in degrees (they're converted to radians internally)
## Author
Luis Padron
*/
Expand All @@ -142,15 +156,15 @@ import UIKit

/**
The end angle for the entire progress ring
Please note that Cocoa Touch uses a clockwise rotating unit circle.
I.e: 90 degrees is at the bottom and 270 degrees is at the top
## Important ##
Default = 360 (degrees)
Values should be in degrees (they're converted to radians internally)
## Author
Luis Padron
*/
Expand All @@ -162,10 +176,10 @@ import UIKit

/**
The width of the outer ring for the progres bar
## Important ##
Default = 10.0
## Author
Luis Padron
*/
Expand All @@ -175,10 +189,10 @@ import UIKit

/**
The color for the outer ring
## Important ##
Default = UIColor.gray
## Author
Luis Padron
*/
Expand All @@ -188,14 +202,14 @@ import UIKit

/**
The style for the tip/cap of the outer ring
Type: `CGLineCap`
## Important ##
Default = CGLineCap.butt
This is only noticible when ring is not a full circle.
## Author
Luis Padron
*/
Expand All @@ -207,10 +221,10 @@ import UIKit

/**
The width of the inner ring for the progres bar
## Important ##
Default = 5.0
## Author
Luis Padron
*/
Expand All @@ -220,10 +234,10 @@ import UIKit

/**
The color of the inner ring for the progres bar
## Important ##
Default = UIColor.blue
## Author
Luis Padron
*/
Expand All @@ -233,12 +247,12 @@ import UIKit

/**
The spacing between the outer ring and inner ring
## Important ##
This only applies when using progressRingStyle = 1
Default = 1
## Author
Luis Padron
*/
Expand All @@ -248,12 +262,12 @@ import UIKit

/**
The style for the tip/cap of the inner ring
Type: `CGLineCap`
## Important ##
Default = CGLineCap.round
## Author
Luis Padron
*/
Expand All @@ -265,11 +279,11 @@ import UIKit

/**
The text color for the value label field
## Important ##
Default = UIColor.black
## Author
Luis Padron
*/
Expand All @@ -281,12 +295,12 @@ import UIKit
The font to be used for the progress indicator.
All font attributes are specified here except for font color, which is done
using `fontColor`.
## Important ##
Default = UIFont.systemFont(ofSize: 18)
## Author
Luis Padron
*/
Expand All @@ -296,10 +310,10 @@ import UIKit

/**
This returns whether or not the ring is currently animating
## Important ##
Get only property
## Author
Luis Padron
*/
Expand All @@ -310,10 +324,10 @@ import UIKit
/**
The direction the circle is drawn in
Example: true -> clockwise
## Important ##
Default = true (draw the circle clockwise)
## Author
Pete Walker
*/
Expand Down Expand Up @@ -527,10 +541,10 @@ import UIKit
/**
This function allows animation of the animatable properties of the `UICircularRing`.
These properties include `innerRingColor, innerRingWidth, outerRingColor, outerRingWidth, innerRingSpacing, fontColor`.
Simply call this function and inside of the animation block change the animatable properties as you would in any `UView`
animation block.
The completion block is called when all animations finish.
*/
open func animateProperties(duration: TimeInterval, animations: () -> Void) {
Expand All @@ -540,10 +554,10 @@ import UIKit
/**
This function allows animation of the animatable properties of the `UICircularRing`.
These properties include `innerRingColor, innerRingWidth, outerRingColor, outerRingWidth, innerRingSpacing, fontColor`.
Simply call this function and inside of the animation block change the animatable properties as you would in any `UView`
animation block.
The completion block is called when all animations finish.
*/
open func animateProperties(duration: TimeInterval, animations: () -> Void,
Expand Down
27 changes: 21 additions & 6 deletions src/UICircularProgressRing/UICircularRingLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ class UICircularRingLayer: CAShapeLayer {
ctx.restoreGState()
}

if let knobStyle = ring.valueKnobStyle, value > minValue {
if let knobStyle = ring.valueKnobStyle, ((value > minValue) || (ring?.shouldDrawMinValueKnob ?? false)) {
let knobOffset = knobStyle.size / 2
drawValueKnob(in: ctx, origin: CGPoint(x: innerPath.currentPoint.x - knobOffset,
y: innerPath.currentPoint.y - knobOffset))
Expand All @@ -265,10 +265,11 @@ class UICircularRingLayer: CAShapeLayer {

case .bordered(let borderWidth, let borderColor):
let center: CGPoint = CGPoint(x: bounds.midX, y: bounds.midY)
let knobSize = valueKnobStyle?.size ?? 0
let offSet = max(ring.outerRingWidth, ring.innerRingWidth) / 2
+ knobSize / 4
+ borderWidth * 2
let offSet: CGFloat = {
let offset = max(ring.outerRingWidth, ring.innerRingWidth) / 2
let size = valueKnobStyle?.size ?? 0
return offset + (size / 4) + (borderWidth * 2)
}()
let outerRadius: CGFloat = min(bounds.width, bounds.height) / 2 - offSet
let borderStartAngle = ring.outerCapStyle == .butt ? ring.startAngle - borderWidth : ring.startAngle
let borderEndAngle = ring.outerCapStyle == .butt ? ring.endAngle + borderWidth : ring.endAngle
Expand Down Expand Up @@ -362,7 +363,7 @@ class UICircularRingLayer: CAShapeLayer {
context.saveGState()

let rect = CGRect(origin: origin, size: CGSize(width: knobStyle.size, height: knobStyle.size))
let knobPath = UIBezierPath(ovalIn: rect)
let knobPath = knobStyle.path.from(rect)

context.setShadow(offset: knobStyle.shadowOffset,
blur: knobStyle.shadowBlur,
Expand All @@ -374,6 +375,20 @@ class UICircularRingLayer: CAShapeLayer {
context.drawPath(using: .fill)

context.restoreGState()

if let image = knobStyle.image {
context.saveGState()

let imageRect = rect.inset(by: knobStyle.imageInsets)
if let tintColor = knobStyle.imageTintColor {
tintColor.setFill()
image.withRenderingMode(.alwaysTemplate).draw(in: imageRect)
} else {
image.draw(in: imageRect)
}

context.restoreGState()
}
}

/**
Expand Down
Loading

0 comments on commit f54ef5f

Please sign in to comment.