From 2fa98b8e0f1f2d8ab5e6e7cd611f250cfe358581 Mon Sep 17 00:00:00 2001 From: isaman kumara Date: Tue, 13 Mar 2018 12:55:41 +0530 Subject: [PATCH 1/4] progress value added to the prgress bar --- .../project.pbxproj | 19 ++- .../Base.lproj/Main.storyboard | 66 +++++++++- .../ProgressViewController.swift | 37 ++++++ HGCircularSlider.podspec | 2 +- HGCircularSlider.xcodeproj/project.pbxproj | 4 + .../Classes/CircularProgressView.swift | 120 ++++++++++++++++++ .../Classes/CircularSlider+Draw.swift | 36 ++++++ HGCircularSlider/Info.plist | 2 +- 8 files changed, 275 insertions(+), 11 deletions(-) create mode 100644 Example/HGCircularSlider/ProgressViewController.swift create mode 100644 HGCircularSlider/Classes/CircularProgressView.swift diff --git a/Example/HGCircularSlider.xcodeproj/project.pbxproj b/Example/HGCircularSlider.xcodeproj/project.pbxproj index 0b34951..9d7d981 100755 --- a/Example/HGCircularSlider.xcodeproj/project.pbxproj +++ b/Example/HGCircularSlider.xcodeproj/project.pbxproj @@ -20,6 +20,8 @@ 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; }; BDF84380A076F46A79D0C634 /* Pods_HGCircularSlider_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 41A4019E034E0265198683A8 /* Pods_HGCircularSlider_Example.framework */; }; + F28250722057B08700AED83D /* ProgressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F28250712057B08700AED83D /* ProgressViewController.swift */; }; + F28250732057B08700AED83D /* ProgressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F28250712057B08700AED83D /* ProgressViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -57,6 +59,7 @@ 9BA305BCC009CE17283FE799 /* Pods-HGCircularSlider_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HGCircularSlider_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-HGCircularSlider_Example/Pods-HGCircularSlider_Example.release.xcconfig"; sourceTree = ""; }; E7D1A678D25EC3365B800DB3 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; EEE4816CB037512E066C24A8 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; + F28250712057B08700AED83D /* ProgressViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -120,6 +123,7 @@ 5539B1B81DD275250038D49D /* PlayerViewController.swift */, 551FF6F11DD3BFE300BD5B76 /* OtherExampleViewController.swift */, 55CE65381DD3D32100B0C2B2 /* OClockViewController.swift */, + F28250712057B08700AED83D /* ProgressViewController.swift */, 607FACD91AFB9204008FA782 /* Main.storyboard */, 5539B1BA1DD276C00038D49D /* StrangeZero.mp3 */, 607FACDC1AFB9204008FA782 /* Images.xcassets */, @@ -290,13 +294,16 @@ files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-HGCircularSlider_Tests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 0F46583D66160DDAEA5B58FE /* [CP] Copy Pods Resources */ = { @@ -320,9 +327,12 @@ files = ( ); inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-HGCircularSlider_Example/Pods-HGCircularSlider_Example-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/HGCircularSlider/HGCircularSlider.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HGCircularSlider.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -365,13 +375,16 @@ files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-HGCircularSlider_Example-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -384,6 +397,7 @@ 551FF6F21DD3BFE300BD5B76 /* OtherExampleViewController.swift in Sources */, 607FACD81AFB9204008FA782 /* ClockViewController.swift in Sources */, 3EC27E521EA546F700631582 /* CircularSliderViewController.swift in Sources */, + F28250722057B08700AED83D /* ProgressViewController.swift in Sources */, 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, 5539B1B91DD275250038D49D /* PlayerViewController.swift in Sources */, 55CE65391DD3D32100B0C2B2 /* OClockViewController.swift in Sources */, @@ -395,6 +409,7 @@ buildActionMask = 2147483647; files = ( 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */, + F28250732057B08700AED83D /* ProgressViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Example/HGCircularSlider/Base.lproj/Main.storyboard b/Example/HGCircularSlider/Base.lproj/Main.storyboard index 481e1b0..2b46a31 100755 --- a/Example/HGCircularSlider/Base.lproj/Main.storyboard +++ b/Example/HGCircularSlider/Base.lproj/Main.storyboard @@ -1,14 +1,20 @@ - + - + + + + + AvenirNext-Regular + + @@ -173,6 +179,7 @@ + @@ -738,6 +745,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -747,9 +804,4 @@ - - - - - diff --git a/Example/HGCircularSlider/ProgressViewController.swift b/Example/HGCircularSlider/ProgressViewController.swift new file mode 100644 index 0000000..f141f09 --- /dev/null +++ b/Example/HGCircularSlider/ProgressViewController.swift @@ -0,0 +1,37 @@ +// +// ProgressViewController.swift +// HGCircularSlider +// +// Created by Saman kumara on 3/13/18. +// Copyright © 2018 CocoaPods. All rights reserved. +// + +import UIKit +import HGCircularSlider + +class ProgressViewController: UIViewController { + @IBOutlet weak var rangeCircularSlider: CircularProgressView! + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + // Get the new view controller using segue.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/HGCircularSlider.podspec b/HGCircularSlider.podspec index b65864d..aae60d5 100644 --- a/HGCircularSlider.podspec +++ b/HGCircularSlider.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |s| s.name = 'HGCircularSlider' -s.version = '2.0.0' +s.version = '2.0.1' s.summary = 'Multiple Circular Sliders used to select a value from a continuous range of values.' diff --git a/HGCircularSlider.xcodeproj/project.pbxproj b/HGCircularSlider.xcodeproj/project.pbxproj index c2caf7c..63a6998 100644 --- a/HGCircularSlider.xcodeproj/project.pbxproj +++ b/HGCircularSlider.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ CCDBFE001E4336C9005D6F08 /* CircularSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCDBFDFA1E4336C9005D6F08 /* CircularSlider.swift */; }; CCDBFE011E4336C9005D6F08 /* CircularSliderHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCDBFDFB1E4336C9005D6F08 /* CircularSliderHelper.swift */; }; CCDBFE021E4336C9005D6F08 /* RangeCircularSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCDBFDFC1E4336C9005D6F08 /* RangeCircularSlider.swift */; }; + F28250702057AF6300AED83D /* CircularProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F282506F2057AF6300AED83D /* CircularProgressView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -26,6 +27,7 @@ CCDBFDFA1E4336C9005D6F08 /* CircularSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularSlider.swift; sourceTree = ""; }; CCDBFDFB1E4336C9005D6F08 /* CircularSliderHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularSliderHelper.swift; sourceTree = ""; }; CCDBFDFC1E4336C9005D6F08 /* RangeCircularSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RangeCircularSlider.swift; sourceTree = ""; }; + F282506F2057AF6300AED83D /* CircularProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularProgressView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -82,6 +84,7 @@ CCDBFDFB1E4336C9005D6F08 /* CircularSliderHelper.swift */, CCCC96451E9F7FD000999D34 /* MidPointCircularSlider.swift */, CCDBFDFC1E4336C9005D6F08 /* RangeCircularSlider.swift */, + F282506F2057AF6300AED83D /* CircularProgressView.swift */, ); path = Classes; sourceTree = ""; @@ -171,6 +174,7 @@ CCDBFE021E4336C9005D6F08 /* RangeCircularSlider.swift in Sources */, CCDBFE001E4336C9005D6F08 /* CircularSlider.swift in Sources */, CCCC96461E9F7FD000999D34 /* MidPointCircularSlider.swift in Sources */, + F28250702057AF6300AED83D /* CircularProgressView.swift in Sources */, CCDBFE011E4336C9005D6F08 /* CircularSliderHelper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/HGCircularSlider/Classes/CircularProgressView.swift b/HGCircularSlider/Classes/CircularProgressView.swift new file mode 100644 index 0000000..5eda476 --- /dev/null +++ b/HGCircularSlider/Classes/CircularProgressView.swift @@ -0,0 +1,120 @@ +// +// CircularProgressView.swift +// HGCircularSlider +// +// Created by Saman kumara on 3/9/18. +// Copyright © 2018 intive. All rights reserved. +// + +import UIKit + + +open class CircularProgressView: CircularSlider { + + /** + * The center of the end thumb + * Used to know in which thumb is the user gesture + */ + fileprivate var endThumbCenter: CGPoint = CGPoint.zero + fileprivate var endLabelCenter: CGPoint = CGPoint.zero + + /** + * If this is true the end thumb will be displyed + * + * The default value of this property is the false. + */ + @IBInspectable + open var showEndThumb: Bool = false + + /** + * The color used to progress value label text color + * + * The default value of this property is the white color. + */ + @IBInspectable + open var progressLabelColor: UIColor = UIColor.white + + /** + * The progress value label text font name + * + * The default value of this property is the Helvetica. + */ + @IBInspectable + open var progressLabelFontName: String = "Helvetica" + + /** + * The progress value label text font size + * + * The default value of this property is the 12.0. + */ + @IBInspectable + open var progressLabelFontSize: CGFloat = 12.0 + + @IBInspectable + open var distance: CGFloat = -1 { + didSet { + assert(distance <= maximumValue - minimumValue, "The distance value is greater than distance between max and min value") + endPointValue = startPointValue + distance + } + } + + open var startPointValue: CGFloat = 0.0 { + didSet { + guard oldValue != startPointValue else { return } + + if startPointValue < minimumValue { + startPointValue = minimumValue + } + + if distance > 0 { + endPointValue = startPointValue + distance + } + + setNeedsDisplay() + } + } + + override open var endPointValue: CGFloat { + didSet { + if oldValue == endPointValue && distance <= 0 { + return + } + + if endPointValue > maximumValue { + endPointValue = maximumValue + } + + if distance > 0 { + startPointValue = endPointValue - distance + } + + setNeedsDisplay() + } + } + + override open func draw(_ rect: CGRect) { + guard let context = UIGraphicsGetCurrentContext() else { return } + + drawCircularSlider(inContext: context) + + let interval = Interval(min: minimumValue, max: maximumValue, rounds: numberOfRounds) + // get start angle from start value + let startAngle = CircularSliderHelper.scaleToAngle(value: startPointValue, inInterval: interval) + CircularSliderHelper.circleInitialAngle + // get end angle from end value + let endAngle = CircularSliderHelper.scaleToAngle(value: endPointValue, inInterval: interval) + CircularSliderHelper.circleInitialAngle + + drawShadowArc(fromAngle: startAngle, toAngle: endAngle, inContext: context) + drawFilledArc(fromAngle: startAngle, toAngle: endAngle, inContext: context) + + // end thumb + if (showEndThumb) { + endThumbTintColor.setFill() + endThumbCenter = drawThumb(withAngle: endAngle, inContext: context) + if let image = endThumbImage { + endThumbCenter = drawThumb(withImage: image, angle: endAngle, inContext: context) + } + } + + endLabelCenter = drawLable(withAngle: endAngle, labelFont: UIFont(name: progressLabelFontName, size: progressLabelFontSize)!, labelFontColor: progressLabelColor, inContext: context) + } +} diff --git a/HGCircularSlider/Classes/CircularSlider+Draw.swift b/HGCircularSlider/Classes/CircularSlider+Draw.swift index 29fe75d..e90c98a 100644 --- a/HGCircularSlider/Classes/CircularSlider+Draw.swift +++ b/HGCircularSlider/Classes/CircularSlider+Draw.swift @@ -137,4 +137,40 @@ extension CircularSlider { return thumbOrigin } + + /** + Draw Progress label and return the coordinates of its center + + - parameter angle: the angle of the point in the main circle + - parameter labelFont: the font of the label + - parameter labelFontColor: the font color of the label + - parameter context: the context + + - returns: return the origin point of the thumb + */ + @discardableResult + internal func drawLable(withAngle angle: CGFloat, labelFont: UIFont, labelFontColor: UIColor, inContext context: CGContext) -> CGPoint { + UIGraphicsPushContext(context) + context.beginPath() + let circle = Circle(origin: bounds.center, radius: self.radius) + let thumbOrigin = CircularSliderHelper.endPoint(fromCircle: circle, angle: angle) + let imageSize = CGSize(width:lineWidth , height: lineWidth) + let imageFrame = CGRect(x: thumbOrigin.x - (imageSize.width / 2), y: thumbOrigin.y - (imageSize.height / 2), width: imageSize.width, height: imageSize.height) + let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle + textStyle.alignment = NSTextAlignment.center + + let textFontAttributes = [ + NSFontAttributeName: labelFont, + NSParagraphStyleAttributeName: textStyle, + NSForegroundColorAttributeName: labelFontColor + ] + + let st = "\(String(format: "%.1f", endPointValue))" as NSString + + st.draw(in: imageFrame, withAttributes: textFontAttributes) + + UIGraphicsPopContext() + + return thumbOrigin + } } diff --git a/HGCircularSlider/Info.plist b/HGCircularSlider/Info.plist index d87c8b3..0e27f5f 100644 --- a/HGCircularSlider/Info.plist +++ b/HGCircularSlider/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.0 + 2.0.1 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass From 4548d097e2895c51f1d93ae349ced4c5ec54e7f4 Mon Sep 17 00:00:00 2001 From: isaman kumara Date: Wed, 14 Mar 2018 09:45:15 +0530 Subject: [PATCH 2/4] added swift 3 and 4 supprot --- .../Classes/CircularSlider+Draw.swift | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/HGCircularSlider/Classes/CircularSlider+Draw.swift b/HGCircularSlider/Classes/CircularSlider+Draw.swift index e90c98a..afb307b 100644 --- a/HGCircularSlider/Classes/CircularSlider+Draw.swift +++ b/HGCircularSlider/Classes/CircularSlider+Draw.swift @@ -159,15 +159,25 @@ extension CircularSlider { let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle textStyle.alignment = NSTextAlignment.center - let textFontAttributes = [ - NSFontAttributeName: labelFont, - NSParagraphStyleAttributeName: textStyle, - NSForegroundColorAttributeName: labelFontColor - ] - let st = "\(String(format: "%.1f", endPointValue))" as NSString - - st.draw(in: imageFrame, withAttributes: textFontAttributes) + + #if swift(>=4.0) + let textFontAttributes = [ + NSAttributedStringKey.font: labelFont, + NSAttributedStringKey.paragraphStyle: textStyle, + NSAttributedStringKey.foregroundColor: labelFontColor + ] + st.draw(in: imageFrame, withAttributes: textFontAttributes) + #elseif swift(>=3.0) + + let textFontAttributes = [ + NSFontAttributeName: labelFont, + NSParagraphStyleAttributeName: textStyle, + NSForegroundColorAttributeName: labelFontColor, + NSBackgroundColorAttributeName: UIColor.red + ] + st.draw(in: imageFrame, withAttributes: textFontAttributes) + #endif UIGraphicsPopContext() From 1b06a06203626b92f6923edfdc76f242ebfb77e5 Mon Sep 17 00:00:00 2001 From: isaman kumara Date: Thu, 15 Mar 2018 08:51:19 +0530 Subject: [PATCH 3/4] add angle text --- .../Classes/CircularSlider+Draw.swift | 212 ++++++++++++++---- 1 file changed, 170 insertions(+), 42 deletions(-) diff --git a/HGCircularSlider/Classes/CircularSlider+Draw.swift b/HGCircularSlider/Classes/CircularSlider+Draw.swift index afb307b..ea6adf4 100644 --- a/HGCircularSlider/Classes/CircularSlider+Draw.swift +++ b/HGCircularSlider/Classes/CircularSlider+Draw.swift @@ -44,38 +44,38 @@ extension CircularSlider { - parameter context: the context */ internal static func drawDisk(withArc arc: Arc, inContext context: CGContext) { - + let circle = arc.circle let origin = circle.origin - + UIGraphicsPushContext(context) context.beginPath() - + context.setLineWidth(0) context.addArc(center: origin, radius: circle.radius, startAngle: arc.startAngle, endAngle: arc.endAngle, clockwise: false) context.addLine(to: CGPoint(x: origin.x, y: origin.y)) context.drawPath(using: .fill) - + UIGraphicsPopContext() } - + // MARK: drawing instance methods - + /// Draw the circular slider internal func drawCircularSlider(inContext context: CGContext) { diskColor.setFill() trackColor.setStroke() - + let circle = Circle(origin: bounds.center, radius: self.radius) let sliderArc = Arc(circle: circle, startAngle: CircularSliderHelper.circleMinValue, endAngle: CircularSliderHelper.circleMaxValue) CircularSlider.drawArc(withArc: sliderArc, lineWidth: backtrackLineWidth, inContext: context) } - + /// draw Filled arc between start an end angles internal func drawFilledArc(fromAngle startAngle: CGFloat, toAngle endAngle: CGFloat, inContext context: CGContext) { diskFillColor.setFill() trackFillColor.setStroke() - + let circle = Circle(origin: bounds.center, radius: self.radius) let arc = Arc(circle: circle, startAngle: startAngle, endAngle: endAngle) @@ -84,18 +84,18 @@ extension CircularSlider { // stroke Arc CircularSlider.drawArc(withArc: arc, lineWidth: lineWidth, mode: .stroke, inContext: context) } - + internal func drawShadowArc(fromAngle startAngle: CGFloat, toAngle endAngle: CGFloat, inContext context: CGContext) { trackShadowColor.setStroke() - + let origin = CGPoint(x: bounds.center.x + trackShadowOffset.x, y: bounds.center.y + trackShadowOffset.y) let circle = Circle(origin: origin, radius: self.radius) let arc = Arc(circle: circle, startAngle: startAngle, endAngle: endAngle) - + // stroke Arc CircularSlider.drawArc(withArc: arc, lineWidth: lineWidth, mode: .stroke, inContext: context) } - + /** Draw the thumb and return the coordinates of its center @@ -110,14 +110,14 @@ extension CircularSlider { let thumbOrigin = CircularSliderHelper.endPoint(fromCircle: circle, angle: angle) let thumbCircle = Circle(origin: thumbOrigin, radius: thumbRadius) let thumbArc = Arc(circle: thumbCircle, startAngle: CircularSliderHelper.circleMinValue, endAngle: CircularSliderHelper.circleMaxValue) - + CircularSlider.drawArc(withArc: thumbArc, lineWidth: thumbLineWidth, inContext: context) return thumbOrigin } - + /** Draw thumb using image and return the coordinates of its center - + - parameter image: the image of the thumb - parameter angle: the angle of the point in the main circle - parameter context: the context @@ -134,16 +134,16 @@ extension CircularSlider { let imageFrame = CGRect(x: thumbOrigin.x - (imageSize.width / 2), y: thumbOrigin.y - (imageSize.height / 2), width: imageSize.width, height: imageSize.height) image.draw(in: imageFrame) UIGraphicsPopContext() - + return thumbOrigin } + /** - Draw Progress label and return the coordinates of its center + Draw thumb using image and return the coordinates of its center + - parameter image: the image of the thumb - parameter angle: the angle of the point in the main circle - - parameter labelFont: the font of the label - - parameter labelFontColor: the font color of the label - parameter context: the context - returns: return the origin point of the thumb @@ -154,33 +154,161 @@ extension CircularSlider { context.beginPath() let circle = Circle(origin: bounds.center, radius: self.radius) let thumbOrigin = CircularSliderHelper.endPoint(fromCircle: circle, angle: angle) - let imageSize = CGSize(width:lineWidth , height: lineWidth) - let imageFrame = CGRect(x: thumbOrigin.x - (imageSize.width / 2), y: thumbOrigin.y - (imageSize.height / 2), width: imageSize.width, height: imageSize.height) - let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle - textStyle.alignment = NSTextAlignment.center - let st = "\(String(format: "%.1f", endPointValue))" as NSString - + let text = "\(String(format: "%.1f", endPointValue))" as NSString + + let size = self.bounds.size + + context.translateBy (x: size.width / 2, y: size.height / 2) + context.scaleBy (x: 1, y: -1) + + var textAngle = angle + if (angle > 0) { + textAngle = angle + CGFloat(Double.pi) + if (angle >= CGFloat(Double.pi / 2)) { + textAngle = angle * -1 + } else { + textAngle = angle + textAngle = textAngle * -1 + } + } else { + textAngle = textAngle * -1 + } + + centreArcPerpendicular(text: text as String, context: context, radius: radius, angle: textAngle , colour: labelFontColor, font: labelFont , clockwise: true) + UIGraphicsPopContext() + + return thumbOrigin + } + + /** + This draws the String str around an arc of radius r, + + - parameter str: the text need to disply + - parameter radius: the radius need to add label + - parameter angle: the angle of the point in the main circle + - parameter c: the color of the label + - parameter font: the font of the label + - parameter clockwise: the text Are we writing clockwise or not + - parameter context: the context + + */ + private func centreArcPerpendicular(text str: String, context: CGContext, radius r: CGFloat, angle theta: CGFloat, colour c: UIColor, font: UIFont, clockwise: Bool){ + + // ******************************************************* + // This draws the String str around an arc of radius r, + // with the text centred at polar angle theta + // ******************************************************* + let l = str.count + var attributes = [NSAttributedStringKey: Any]() + #if swift(>=4.0) - let textFontAttributes = [ - NSAttributedStringKey.font: labelFont, - NSAttributedStringKey.paragraphStyle: textStyle, - NSAttributedStringKey.foregroundColor: labelFontColor - ] - st.draw(in: imageFrame, withAttributes: textFontAttributes) + attributes = [NSAttributedStringKey.font : font] #elseif swift(>=3.0) - - let textFontAttributes = [ - NSFontAttributeName: labelFont, - NSParagraphStyleAttributeName: textStyle, - NSForegroundColorAttributeName: labelFontColor, - NSBackgroundColorAttributeName: UIColor.red - ] - st.draw(in: imageFrame, withAttributes: textFontAttributes) + attributes = [NSFontAttributeName as NSString: font] #endif - UIGraphicsPopContext() + let characters: [String] = str.map { String($0) } // An array of single character strings, each character in str + var arcs: [CGFloat] = [] // This will be the arcs subtended by each character + var totalArc: CGFloat = 0 // ... and the total arc subtended by the string - return thumbOrigin + // Calculate the arc subtended by each letter and their total + for i in 0 ..< l { + var offset = CGSize(); + #if swift(>=4.0) + offset = characters[i].size(withAttributes: attributes) + #elseif swift(>=3.0) + offset = characters[i].size(attributes: attributes as [String : Any]) + #endif + arcs += [chordToArc(offset.width, radius: r)] + totalArc += arcs[i] + } + + + // Are we writing clockwise (right way up at 12 o'clock, upside down at 6 o'clock) + // or anti-clockwise (right way up at 6 o'clock)? + let direction: CGFloat = clockwise ? -1 : 1 + let slantCorrection = clockwise ? -CGFloat(Double.pi / 2) : CGFloat(Double.pi / 2) + + // The centre of the first character will then be at + //var thetaI = theta - totalArc / 2 + arcs[0] / 2 + // But we add the last term inside the loop + var thetaI = theta - direction * totalArc + + for i in 0 ..< l { + thetaI += direction * arcs[i] / 2 + // Call centerText with each character in turn. + // Remember to add +/-90º to the slantAngle otherwise + // the characters will "stack" round the arc rather than "text flow" + centre(text: characters[i], context: context, radius: r, angle: thetaI, colour: c, font: font, slantAngle: thetaI + slantCorrection) + // The centre of the next character will then be at + // thetaI = thetaI + arcs[i] / 2 + arcs[i + 1] / 2 + // but again we leave the last term to the start of the next loop... + thetaI += direction * arcs[i] / 2 + } + } + + /** + Simple geometry + + */ + private func chordToArc(_ chord: CGFloat, radius: CGFloat) -> CGFloat { + return 2 * asin(chord / (2 * radius)) + } + + + /** + This draws the String str centred at the position + + - parameter str: the text need to disply + - parameter radius: the radius need to add label + - parameter angle: the angle of the point in the main circle + - parameter c: the color of the label + - parameter font: the font of the label + - parameter slantAngle: the text angle + - parameter context: the context + + */ + private func centre(text str: String, context: CGContext, radius r:CGFloat, angle theta: CGFloat, colour c: UIColor, font: UIFont, slantAngle: CGFloat) { + // ******************************************************* + // This draws the String str centred at the position + // specified by the polar coordinates (r, theta) + // i.e. the x= r * cos(theta) y= r * sin(theta) + // and rotated by the angle slantAngle + // ******************************************************* + + // Set the text attributes + var attributes = [NSAttributedStringKey: Any]() + + #if swift(>=4.0) + attributes = [NSAttributedStringKey.font : font, + NSAttributedStringKey.foregroundColor: c] + #elseif swift(>=3.0) + attributes = [NSFontAttributeName as NSString: font, + NSForegroundColorAttributeName as NSString: c] + #endif + + // Save the context + context.saveGState() + // Undo the inversion of the Y-axis (or the text goes backwards!) + context.scaleBy(x: 1, y: -1) + // Move the origin to the centre of the text (negating the y-axis manually) + context.translateBy(x: r * cos(theta), y: -(r * sin(theta))) + // Rotate the coordinate system + context.rotate(by: -slantAngle) + // Calculate the width of the text + var offset = CGSize(); + #if swift(>=4.0) + offset = str.size(withAttributes: attributes) + #elseif swift(>=3.0) + offset = str.size(attributes: attributes as [String : Any]) + #endif + // Move the origin by half the size of the text + context.translateBy (x: -offset.width / 2, y: -offset.height / 2) // Move the origin to the centre of the text (negating the y-axis manually) + // Draw the text + str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes as [String : Any]) + // Restore the context + context.restoreGState() } } + From 7ffc47529a116bf937a9e287fc1ba7d53b79199a Mon Sep 17 00:00:00 2001 From: isaman kumara Date: Thu, 15 Mar 2018 09:08:16 +0530 Subject: [PATCH 4/4] fixed swift 4 issue --- HGCircularSlider/Classes/CircularSlider+Draw.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HGCircularSlider/Classes/CircularSlider+Draw.swift b/HGCircularSlider/Classes/CircularSlider+Draw.swift index ea6adf4..c98781c 100644 --- a/HGCircularSlider/Classes/CircularSlider+Draw.swift +++ b/HGCircularSlider/Classes/CircularSlider+Draw.swift @@ -306,7 +306,7 @@ extension CircularSlider { // Move the origin by half the size of the text context.translateBy (x: -offset.width / 2, y: -offset.height / 2) // Move the origin to the centre of the text (negating the y-axis manually) // Draw the text - str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes as [String : Any]) + str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes) // Restore the context context.restoreGState() }