30 Commits

Author SHA1 Message Date
Jalal Ouraigua 575870634b Version correction 2018-12-07 05:10:31 +00:00
Jalal Ouraigua c46a8f1d6d Version Update 2018-12-07 04:54:58 +00:00
Jalal Ouraigua 55848a3e19 Version Update 2018-12-07 04:43:47 +00:00
Jalal Ouraigua 618997aad4 Add CHANGELOG 2018-12-07 04:36:51 +00:00
Jalal Ouraigua 37e2b00592 Update README.md 2018-12-07 04:26:12 +00:00
Jalal Ouraigua 7bfecda8cf Update README.md 2018-12-07 04:10:47 +00:00
Jalal Ouraigua bbf3a808a5 Update README.md 2018-12-07 03:53:01 +00:00
Jalal Ouraigua e29d401afb Update README 2018-12-07 03:43:37 +00:00
Jalal Ouraigua cb1c3e69ce Version Update 2018-12-06 23:31:09 +00:00
Jalal Ouraigua dacd603bf2 Version update 2018-12-06 23:19:34 +00:00
Jalal Ouraigua 73627d9022 Updated podspec 2018-12-06 23:02:50 +00:00
Jalal Ouraigua a31dcae100 Merge branch 'develop' 2018-12-06 22:48:08 +00:00
Jalal Ouraigua 160ca7f711 UI update 2018-12-06 22:47:47 +00:00
Jalal Ouraigua 5f128332e9 Merge remote-tracking branch 'refs/remotes/origin/master' 2018-12-06 21:51:23 +00:00
Jalal Ouraigua f210ead216 Merge branch 'develop' 2018-12-06 21:50:22 +00:00
Jalal Ouraigua 4e7e603dab Screenshots optimised 2018-12-06 21:49:54 +00:00
Jalal Ouraigua e60b145b72 Update README.md 2018-12-06 17:22:08 +00:00
Jalal Ouraigua 17a8ab0b98 Updated podspec 2018-12-06 16:34:02 +00:00
Jalal Ouraigua 1eeadce9c8 Updated README 2018-12-06 16:27:57 +00:00
Jalal Ouraigua 4c5d5383f8 Tweak the UI and Add extra screenshots 2018-12-06 15:32:21 +00:00
Jalal Ouraigua c69c0e7085 Merge remote-tracking branch 'refs/remotes/origin/master' 2018-12-06 06:35:59 +00:00
Jalal Ouraigua 3918db0fd1 Added a new screenshot 2018-12-06 06:33:49 +00:00
ouraigua 64ee9db7b2 Update README.md 2018-12-06 02:57:26 +00:00
ouraigua 0572d26799 Update README.md 2018-12-06 02:56:42 +00:00
Jalal Ouraigua 127d7daf3a Updated README and added first screenshot 2018-12-06 02:42:15 +00:00
Jalal Ouraigua 05b1fbdf76 Initial commit 2018-12-06 01:19:54 +00:00
Jalal Ouraigua 707efd2f49 Updated podspec 2018-12-05 23:40:25 +00:00
Jalal Ouraigua 1ed2848a53 Swift conversion to 4.2 2018-12-05 23:17:57 +00:00
Jalal Ouraigua 8a3ce6a735 Pod setup 2018-12-05 23:16:15 +00:00
Jalal Ouraigua 7b160cda94 Initial commit 2018-12-05 23:05:26 +00:00
18 changed files with 256 additions and 305 deletions
-10
View File
@@ -1,10 +0,0 @@
{
"SWIFT": {
"TOO_MANY_IVARS": [8, 12, 16, 20],
"TOO_MANY_FUNCTIONS": [46, 55, 65, 85],
"ARITY" : [5, 6, 7, 8],
"ABC": [15, 25, 50, 70],
"TOTAL_COMPLEXITY": [100, 180, 280, 400],
"TOTAL_LOC": [200, 250, 320, 450]
}
}
-1
View File
@@ -1 +0,0 @@
jazzy --podspec JOCircularSlider.podspec
@@ -13,15 +13,10 @@
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; };
9A9536F8A95805979063DD22 /* Pods_JOCircularSlider_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CC0EF1308BF44BE0466D9BF /* Pods_JOCircularSlider_Example.framework */; };
AF4F276921BB942500D39C60 /* .jazzy_cmd.yaml in Resources */ = {isa = PBXBuildFile; fileRef = AF4F276821BB942500D39C60 /* .jazzy_cmd.yaml */; };
AF737E2421B89B2B00BFBE5E /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF737E2321B89B2B00BFBE5E /* GradientView.swift */; };
AF737E2621B89F8000BFBE5E /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF737E2521B89F8000BFBE5E /* Utils.swift */; };
AF737E2921B8D60400BFBE5E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AF737E2721B8D60400BFBE5E /* LaunchScreen.storyboard */; };
AF737E2B21B8D71900BFBE5E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AF737E2A21B8D71900BFBE5E /* Assets.xcassets */; };
AFB6605421BB1F2000E22629 /* .codebeatsettings in Resources */ = {isa = PBXBuildFile; fileRef = AFB6605321BB1F2000E22629 /* .codebeatsettings */; };
AFB6605821BB1F3300E22629 /* .swift-version in Resources */ = {isa = PBXBuildFile; fileRef = AFB6605521BB1F3300E22629 /* .swift-version */; };
AFB6605921BB1F3300E22629 /* .travis.yml in Resources */ = {isa = PBXBuildFile; fileRef = AFB6605621BB1F3300E22629 /* .travis.yml */; };
AFB6605A21BB1F3300E22629 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = AFB6605721BB1F3300E22629 /* .gitignore */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -49,15 +44,10 @@
857FCA310632359F6C66CC65 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
9ED6373888E3CDF94E3F8213 /* Pods-JOCircularSlider_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JOCircularSlider_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JOCircularSlider_Tests/Pods-JOCircularSlider_Tests.debug.xcconfig"; sourceTree = "<group>"; };
A310FF740AC505A50DEF761C /* Pods-JOCircularSlider_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JOCircularSlider_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-JOCircularSlider_Tests/Pods-JOCircularSlider_Tests.release.xcconfig"; sourceTree = "<group>"; };
AF4F276821BB942500D39C60 /* .jazzy_cmd.yaml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = .jazzy_cmd.yaml; path = ../.jazzy_cmd.yaml; sourceTree = "<group>"; };
AF737E2321B89B2B00BFBE5E /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = "<group>"; };
AF737E2521B89F8000BFBE5E /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
AF737E2821B8D60400BFBE5E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
AF737E2A21B8D71900BFBE5E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
AFB6605321BB1F2000E22629 /* .codebeatsettings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = .codebeatsettings; path = ../.codebeatsettings; sourceTree = "<group>"; };
AFB6605521BB1F3300E22629 /* .swift-version */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = ".swift-version"; path = "../.swift-version"; sourceTree = "<group>"; };
AFB6605621BB1F3300E22629 /* .travis.yml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = .travis.yml; path = ../.travis.yml; sourceTree = "<group>"; };
AFB6605721BB1F3300E22629 /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = .gitignore; path = ../.gitignore; sourceTree = "<group>"; };
B53C2541DC14B9F694325C57 /* Pods-JOCircularSlider_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JOCircularSlider_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JOCircularSlider_Example/Pods-JOCircularSlider_Example.debug.xcconfig"; sourceTree = "<group>"; };
D0CC336CBAD390916FD5F8FE /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
D1B349DAD0AE068D7095DAFC /* Pods-JOCircularSlider_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JOCircularSlider_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-JOCircularSlider_Example/Pods-JOCircularSlider_Example.release.xcconfig"; sourceTree = "<group>"; };
@@ -171,11 +161,6 @@
7B49D36A49F9D30C4E298C6D /* JOCircularSlider.podspec */,
857FCA310632359F6C66CC65 /* README.md */,
D0CC336CBAD390916FD5F8FE /* LICENSE */,
AFB6605321BB1F2000E22629 /* .codebeatsettings */,
AFB6605721BB1F3300E22629 /* .gitignore */,
AFB6605521BB1F3300E22629 /* .swift-version */,
AFB6605621BB1F3300E22629 /* .travis.yml */,
AF4F276821BB942500D39C60 /* .jazzy_cmd.yaml */,
);
name = "Podspec Metadata";
sourceTree = "<group>";
@@ -268,14 +253,9 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AFB6605921BB1F3300E22629 /* .travis.yml in Resources */,
AFB6605A21BB1F3300E22629 /* .gitignore in Resources */,
AF737E2921B8D60400BFBE5E /* LaunchScreen.storyboard in Resources */,
AF737E2B21B8D71900BFBE5E /* Assets.xcassets in Resources */,
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */,
AF4F276921BB942500D39C60 /* .jazzy_cmd.yaml in Resources */,
AFB6605421BB1F2000E22629 /* .codebeatsettings in Resources */,
AFB6605821BB1F3300E22629 /* .swift-version in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="T5Y-X3-uD8">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="T5Y-X3-uD8">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -39,13 +39,13 @@
<color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="color2">
<color key="value" red="0.15294117647058825" green="0.1803921568627451" blue="0.2196078431372549" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="value" red="0.15235996039999999" green="0.17974209029999999" blue="0.22156283139999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="color1">
<color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="color4">
<color key="value" red="0.13333333333333333" green="0.14509803921568626" blue="0.17254901960784313" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="value" red="0.13288810049999999" green="0.14611955109999999" blue="0.1740877602" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="maxidotOffColor">
<color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -57,7 +57,7 @@
<color key="value" red="1" green="0.5" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="highlightColor">
<color key="value" red="0.33725490196078434" green="0.36470588235294116" blue="0.42352941176470588" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="value" red="0.33810979099999999" green="0.36411823659999998" blue="0.42480460930000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="textColor">
<color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -70,7 +70,7 @@
<real key="value" value="0.80000000000000004"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="pointerColor2">
<color key="value" red="0.25490196078431371" green="0.27058823529411763" blue="0.31764705882352939" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="value" red="0.2530443235" green="0.27250927159999999" blue="0.31792748339999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="pointerColor1">
<color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -87,7 +87,7 @@
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="14" translatesAutoresizingMaskIntoConstraints="NO" id="6nV-kU-kJg">
<rect key="frame" x="41.5" y="565" width="331" height="257"/>
<subviews>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.85999999999999999" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="Yng-5x-Nhy" customClass="DesignableSlider" customModule="JOCircularSlider_Example" customModuleProvider="target">
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.86000001430511475" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="Yng-5x-Nhy" customClass="DesignableSlider" customModule="JOCircularSlider_Example" customModuleProvider="target">
<rect key="frame" x="-2" y="0.0" width="335" height="16"/>
<color key="tintColor" red="0.20392156859999999" green="0.23529411759999999" blue="0.28235294119999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="maximumTrackTintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
@@ -197,7 +197,7 @@
<viewLayoutGuide key="safeArea" id="zts-4c-D2G"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="color1">
<color key="value" red="0.10980392156862745" green="0.12941176470588234" blue="0.15686274509803921" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="value" red="0.10980392160000001" green="0.12941176469999999" blue="0.15686274510000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="color2">
<color key="value" red="0.1333333333" green="0.14117647059999999" blue="0.1647058824" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.0.1</string>
<string>1.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+4 -29
View File
@@ -11,14 +11,7 @@ import JOCircularSlider
class ViewController: UIViewController {
@IBOutlet weak var circularSlider: CircularSlider! {
didSet {
circularSlider.addTarget(self, action: #selector(handleValueChanged(_:)), for: .valueChanged)
circularSlider.addTarget(self, action: #selector(didBeginEditing), for: .editingDidBegin)
circularSlider.addTarget(self, action: #selector(didEndEditing), for: .editingDidEnd)
}
}
@IBOutlet weak var circularSlider: CircularSlider!
@IBOutlet weak var stackView: UIStackView!
@IBOutlet weak var widthConstraint: NSLayoutConstraint! {
didSet {
@@ -78,8 +71,7 @@ class ViewController: UIViewController {
circularSlider.startAngle = direction.startAngle
circularSlider.endAngle = direction.endAngle
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
let value = self.circularSlider.value
self.circularSlider.value = value
self.circularSlider.setValue(self.circularSlider.value, isPercentage: true)
}
}
@@ -112,8 +104,8 @@ class ViewController: UIViewController {
circularSlider.knobMiddleCircleMultiplier = newMultiplier
}
let value = circularSlider.value
circularSlider.value = value
circularSlider.setValue(circularSlider.value, isPercentage: true)
}
@IBAction private func changeDotCount(_ sender: UISlider) {
@@ -125,23 +117,6 @@ class ViewController: UIViewController {
circularSlider.maxidotOnColor = UIColor(hue: CGFloat(sender.value), saturation: 1, brightness: 1, alpha: 1)
}
@objc func didBeginEditing() {
print("\n" + "didBeginEditing\n")
}
@objc func didEndEditing() {
print("\n" + "didBeginEditing\n")
}
@IBAction func handleValueChanged(_ sender: CircularSlider) {
print("value: \(sender.value)")
// If you need to override the formatting of the text in the
// label, then use this.
// circularSlider.setLabelText(String(format: "%.3f", sender.value))
}
}
+1 -2
View File
@@ -335,7 +335,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0930;
LastUpgradeCheck = 1010;
LastUpgradeCheck = 0930;
};
buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */;
compatibilityVersion = "Xcode 3.2";
@@ -559,7 +559,6 @@
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
STRIP_INSTALLED_PRODUCT = NO;
SWIFT_COMPILATION_MODE = wholemodule;
SYMROOT = "${SRCROOT}/../build";
};
name = Release;
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.1</string>
<string>1.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.1</string>
<string>1.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.1</string>
<string>1.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+1 -3
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'JOCircularSlider'
s.version = '2.0.1'
s.version = '1.0.3'
s.summary = 'A highly customisable and reusable iOS circular slider.'
# This description is used to generate tags and improve search results.
@@ -33,8 +33,6 @@ Pod::Spec.new do |s|
s.ios.deployment_target = '10.0'
s.source_files = 'JOCircularSlider/Classes/**/*'
s.documentation_url = 'http://ouraigua.com/github/jocircularslider/docs/index.html'
# s.resource_bundles = {
# 'JOCircularSlider' => ['JOCircularSlider/Assets/*.png']
+153 -140
View File
@@ -31,7 +31,7 @@ public struct Constants {
public static let dotBlueColor = UIColor(red: 31/255.0, green: 206/255.0, blue: 252/255.0, alpha: 1)
public static let dotRedColor = UIColor(red: 248/255.0, green: 16/255.0, blue: 32/255.0, alpha: 1)
public static let dotOrangeColor = UIColor(red: 1, green: 128/255.0, blue: 0, alpha: 1)
public static let dotGrayColor = lightColor4
public static let dotGrayColor = UIColor(red: 206/255.0, green: 206/255.0, blue: 206/255.0, alpha: 1)
public static let dotShadowOffset = CGSize(width: 2, height: 2)
public static let outerMultiplier : CGFloat = 0.86
@@ -44,22 +44,26 @@ open class CircularSlider: UIControl {
// MARK: - Public API
@IBInspectable open var color1: UIColor {
@IBInspectable
open var color1: UIColor {
get { return renderer.knobView.color1 }
set { renderer.knobView.color1 = newValue }
}
@IBInspectable open var color2: UIColor {
@IBInspectable
open var color2: UIColor {
get { return renderer.knobView.color2 }
set { renderer.knobView.color2 = newValue}
}
@IBInspectable open var color3: UIColor {
@IBInspectable
open var color3: UIColor {
get { return renderer.knobView.color3 }
set { renderer.knobView.color3 = newValue}
}
@IBInspectable open var color4: UIColor {
@IBInspectable
open var color4: UIColor {
get { return renderer.knobView.color4 }
set {
renderer.knobView.color4 = newValue
@@ -67,7 +71,8 @@ open class CircularSlider: UIControl {
}
}
@IBInspectable open var highlightColor: UIColor {
@IBInspectable
open var highlightColor: UIColor {
get { return renderer.knobView.highlightColor }
set {
renderer.knobView.highlightColor = newValue
@@ -78,7 +83,8 @@ open class CircularSlider: UIControl {
}
}
@IBInspectable open var knobOuterCircleMultiplier: CGFloat {
@IBInspectable
open var knobOuterCircleMultiplier: CGFloat {
get { return renderer.knobView.outerCircleMultiplier }
set {
renderer.knobView.outerCircleMultiplier = newValue
@@ -87,69 +93,82 @@ open class CircularSlider: UIControl {
}
}
@IBInspectable open var knobMiddleCircleMultiplier: CGFloat {
@IBInspectable
open var knobMiddleCircleMultiplier: CGFloat {
get { return renderer.knobView.middleCircleMultiplier }
set {
renderer.knobView.middleCircleMultiplier = newValue
}
}
@IBInspectable open var knobInnerCircleMultiplier: CGFloat {
@IBInspectable
open var knobInnerCircleMultiplier: CGFloat {
get { return renderer.knobView.innerCircleMultiplier }
set { renderer.knobView.innerCircleMultiplier = newValue }
}
@IBInspectable open var knobShadowOpacity: Float {
@IBInspectable
open var knobShadowOpacity: Float {
get { return renderer.knobView.shadowOpacity }
set { renderer.knobView.shadowOpacity = newValue }
}
@IBInspectable open var pointerDistanceFromInnerCircleEdge: CGFloat {
@IBInspectable
open var pointerDistanceFromInnerCircleEdge: CGFloat {
get { return renderer.pointerViewDistanceFromEdge }
set { renderer.pointerViewDistanceFromEdge = newValue }
}
@IBInspectable open var pointerSizeMultiplier: CGFloat {
@IBInspectable
open var pointerSizeMultiplier: CGFloat {
get { return renderer.pointerViewMultiplier }
set { renderer.pointerViewMultiplier = newValue }
}
@IBInspectable open var pointerColor1: UIColor {
@IBInspectable
open var pointerColor1: UIColor {
get { return renderer.pointerView.color1 }
set { renderer.pointerView.color1 = newValue }
}
@IBInspectable open var pointerColor2: UIColor {
@IBInspectable
open var pointerColor2: UIColor {
get { return renderer.pointerView.color2 }
set { renderer.pointerView.color2 = newValue }
}
@IBInspectable open var textIsHidden: Bool {
@IBInspectable
open var textIsHidden: Bool {
get { return renderer.textFieldIsHidden }
set { renderer.textFieldIsHidden = newValue}
}
@IBInspectable open var textFontSizeMultiplier: CGFloat {
@IBInspectable
open var textFontSizeMultiplier: CGFloat {
get { return renderer.fontSizeMultiplier }
set { renderer.fontSizeMultiplier = newValue}
}
@IBInspectable open var textColor: UIColor {
@IBInspectable
open var textColor: UIColor {
get { return renderer.textField.textColor! }
set { renderer.textField.textColor = newValue}
}
@IBInspectable open var maxidotViewIsHidden: Bool {
@IBInspectable
open var maxidotViewIsHidden: Bool {
get { return renderer.maxiDotView.isHidden }
set { renderer.maxiDotView.isHidden = newValue }
}
@IBInspectable open var maxidotOffColor: UIColor {
@IBInspectable
open var maxidotOffColor: UIColor {
get { return renderer.maxiDotView.offColor }
set { renderer.maxiDotView.offColor = newValue }
}
@IBInspectable open var maxidotOnColor: UIColor {
@IBInspectable
open var maxidotOnColor: UIColor {
get { return renderer.maxiDotView.onColor }
set {
renderer.maxiDotView.onColor = newValue
@@ -158,12 +177,14 @@ open class CircularSlider: UIControl {
}
}
@IBInspectable open var maxidotMaxColor: UIColor {
@IBInspectable
open var maxidotMaxColor: UIColor {
get { return renderer.maxiDotView.maxColor }
set { renderer.maxiDotView.maxColor = newValue }
}
@IBInspectable open var maxidotCount: Int {
@IBInspectable
open var maxidotCount: Int {
get { return renderer.maxiDotView.maxiDotCount }
set {
let value = newValue % 2 == 0 ? newValue + 1 : newValue
@@ -174,37 +195,44 @@ open class CircularSlider: UIControl {
}
}
@IBInspectable open var maxidotRadiusMultiplier: CGFloat {
@IBInspectable
open var maxidotRadiusMultiplier: CGFloat {
get { return renderer.maxiDotView.dotRadiusMultiplier }
set { renderer.maxiDotView.dotRadiusMultiplier = newValue }
}
@IBInspectable open var maxidotInset: CGFloat {
@IBInspectable
open var maxidotInset: CGFloat {
get { return renderer.maxiDotView.dotInset }
set { renderer.maxiDotView.dotInset = newValue }
}
@IBInspectable open var maxidotMaxDotCount: Int {
@IBInspectable
open var maxidotMaxDotCount: Int {
get { return renderer.maxiDotView.maxDotCount }
set { renderer.maxiDotView.maxDotCount = newValue }
}
@IBInspectable open var minidotViewIsHidden: Bool {
@IBInspectable
open var minidotViewIsHidden: Bool {
get { return renderer.miniDotView.isHidden }
set { renderer.miniDotView.isHidden = newValue }
}
@IBInspectable open var minidotColor: UIColor {
@IBInspectable
open var minidotColor: UIColor {
get { return renderer.miniDotView.offColor }
set { renderer.miniDotView.offColor = newValue }
}
@IBInspectable open var minidotHighlightColor: UIColor {
@IBInspectable
open var minidotHighlightColor: UIColor {
get { return renderer.miniDotView.highlightColor ?? .white }
set { renderer.miniDotView.highlightColor = newValue }
}
@IBInspectable open var minidotCountPerSegment: Int {
@IBInspectable
open var minidotCountPerSegment: Int {
get { return renderer.miniDotView.dotCountPerSegment }
set {
renderer.miniDotView.dotCountPerSegment = newValue
@@ -212,83 +240,114 @@ open class CircularSlider: UIControl {
}
}
@IBInspectable open var minidotRadiusMultiplier: CGFloat {
@IBInspectable
open var minidotRadiusMultiplier: CGFloat {
get { return renderer.miniDotView.dotRadiusMultiplier }
set { renderer.miniDotView.dotRadiusMultiplier = newValue }
}
@IBInspectable open var minidotInset: CGFloat {
@IBInspectable
open var minidotInset: CGFloat {
get { return renderer.miniDotView.dotInset }
set { renderer.miniDotView.dotInset = newValue }
}
@IBInspectable open var minidotHideHighlight: Bool {
@IBInspectable
open var minidotHideHighlight: Bool {
get { return renderer.miniDotView.highlightColor != nil }
set { renderer.miniDotView.highlightColor = newValue ? highlightColor : nil }
}
/**
This value will be pinned to minimumValue/maximumValue
The default value of this property is 0.0.
*/
@IBInspectable open var value: CGFloat { // always min <= value <= max
get { return CGFloat(renderer.value) * (maximumValue - minimumValue) + minimumValue }
@IBInspectable
open var minimumValue: CGFloat {
get { return CGFloat(renderer.minimumValue) }
set {
guard maximumValue >= minimumValue else {
fatalError("`maximumValue` should be greater then `minimumValue`.")
}
let rangedValue = min(maximumValue, max(minimumValue, newValue))
renderer.value = Float((rangedValue - minimumValue) / (maximumValue - minimumValue))
renderer.minimumValue = Float(newValue)
setValue(value, isPercentage: true)
}
}
@IBInspectable open var minimumValue: CGFloat = 0
@IBInspectable
open var maximumValue: CGFloat {
get { return CGFloat(renderer.maximumValue) }
set {
renderer.maximumValue = Float(newValue)
setValue(value, isPercentage: true)
}
}
@IBInspectable open var maximumValue: CGFloat = 100
@IBInspectable open var startAngle: CGFloat {
@IBInspectable
open var startAngle: CGFloat {
get { return renderer.startAngle.toDegree }
set { renderer.startAngle = newValue.toRadian }
}
@IBInspectable open var endAngle: CGFloat {
@IBInspectable
open var endAngle: CGFloat {
get { return renderer.endAngle.toDegree }
set { renderer.endAngle = newValue.toRadian }
}
@IBInspectable open var isClockwise: Bool {
@IBInspectable
open var isClockwise: Bool {
get { return renderer.isClockwise }
set { renderer.isClockwise = newValue }
}
@IBInspectable open var isNegative: Bool {
get { return renderer.isNegative }
set { renderer.isNegative = newValue }
}
@IBInspectable open var labelDecimalPlaces: Int = 0
// MARK: - Private Properties
lazy private var renderer = Renderer(with: self)
private var lastTouchAngle: CGFloat = 0
open private (set) var value: Float = 0 // 0 <= value <= 1
private var centerPoint: CGPoint { return CGPoint(x: bounds.midX, y: bounds.midY) }
// MARK: - Functions
override public init(frame: CGRect) {
super.init(frame: frame)
value = minimumValue
setValue(renderer.minimumValue)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
value = minimumValue
setValue(renderer.minimumValue)
}
override open func layoutSubviews() {
super.layoutSubviews()
renderer.updateUI(in: bounds)
renderer.update(bounds, value: value)
}
// MARK: - Public
open func setValue(_ newValue: Float, isPercentage: Bool = false) {
guard maximumValue > minimumValue else {
fatalError("`maximumValue` should be greater then `minimumValue`.")
}
if isPercentage {
value = min(1, max(0, newValue))
} else {
// convert to percentage
let rangedValue = min(renderer.maximumValue, max(renderer.minimumValue, newValue))
value = (rangedValue - renderer.minimumValue) / (renderer.maximumValue - renderer.minimumValue)
}
// updates
renderer.updateText(with: value)
renderer.updatePointerView(in: bounds, value: value)
renderer.maxiDotView.updateColors(using: value)
}
open func setTextFont(named: String, textColor: UIColor, multiplier: CGFloat) {
textFontSizeMultiplier = multiplier
let textSize = bounds.height * multiplier
renderer.setTextFont(named: named, textColor: textColor, textSize: textSize)
}
open func setTextShadow(color: UIColor, opacity: Float = 1, offset: CGSize = CGSize(width: 1, height: 1), radius: CGFloat = 0) {
renderer.setTextShadow(color: color, opacity: opacity, offset: offset, radius: radius)
}
// MARK: - Touches
@@ -299,7 +358,6 @@ open class CircularSlider: UIControl {
let distanceToOrigin = location - centerPoint
lastTouchAngle = atan2(distanceToOrigin.y, distanceToOrigin.x).toDegree
sendActions(for: .editingDidBegin)
}
override open func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
@@ -316,30 +374,8 @@ open class CircularSlider: UIControl {
let angelDeltaAsPercentage = Float(angelDelta / angleRange)
guard abs(angelDeltaAsPercentage) < 1 else { return }
let newValue = renderer.value + (isClockwise ? angelDeltaAsPercentage : -angelDeltaAsPercentage)
renderer.value = max(0, min(newValue, 1))
}
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
sendActions(for: .editingDidEnd)
}
// MARK: - Public
open func setLabelFont(named: String, textColor: UIColor, multiplier: CGFloat) {
textFontSizeMultiplier = multiplier
let textSize = bounds.height * multiplier
renderer.setTextFont(named: named, textColor: textColor, textSize: textSize)
}
open func setLabelShadow(color: UIColor, opacity: Float = 1, offset: CGSize = CGSize(width: 1, height: 1), radius: CGFloat = 0) {
renderer.setTextShadow(color: color, opacity: opacity, offset: offset, radius: radius)
}
open func setLabelText(_ text: String?) {
renderer.textField.text = text
let newValue = isClockwise ? value + angelDeltaAsPercentage : value - angelDeltaAsPercentage
setValue(newValue, isPercentage: true)
}
}
@@ -362,11 +398,6 @@ class Renderer {
maxiDotView.isClockwise = isClockwise
}
}
fileprivate var isNegative: Bool = false {
didSet {
}
}
fileprivate var textFieldIsHidden: Bool = false
fileprivate var fontSizeMultiplier: CGFloat = 0.5
@@ -387,18 +418,9 @@ class Renderer {
}
}
fileprivate var value: Float = 0.0 { // 0 <= renderer.value <= 1
didSet {
// updates
updateText()
if let bounds = circularSlider?.bounds {
updatePointerView(in: bounds)
}
maxiDotView.updateColors(using: value)
fileprivate var minimumValue: Float = 0.0
fileprivate var maximumValue: Float = 100.0
circularSlider?.sendActions(for: .valueChanged)
}
}
// MARK: - Init
@@ -407,8 +429,8 @@ class Renderer {
commonInit()
}
func updateUI(in bounds: CGRect) {
updatePointerView(in: bounds)
func update(_ bounds: CGRect, value: Float) {
updatePointerView(in: bounds, value: value)
updateTextField(in: bounds)
updateDotViews(in: bounds)
}
@@ -438,28 +460,28 @@ private extension Renderer {
circularSlider?.addSubview(knobView)
knobView.translatesAutoresizingMaskIntoConstraints = false
let views = ["view": knobView]
let verticalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|", options: .init(rawValue: 0), metrics: nil, views: views)
let horizontalConstraint = NSLayoutConstraint.constraints(withVisualFormat: "H:|[view]|", options: .init(rawValue: 0), metrics: nil, views: views)
circularSlider?.addConstraints(verticalConstraint + horizontalConstraint)
circularSlider?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|", options: .init(rawValue: 0), metrics: nil, views: views))
circularSlider?.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[view]|", options: .init(rawValue: 0), metrics: nil, views: views))
}
func addPointerView() {
circularSlider?.addSubview(pointerView)
}
func addInputAccessoryView() {
let width = UIScreen.main.bounds.width
let toolBar = UIToolbar(frame: CGRect(origin: .zero, size: CGSize(width: width, height: 48)))
toolBar.barStyle = .blackTranslucent
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(keyboardDoneButtonTapped))
done.tintColor = .lightGray
toolBar.items = [done, flexibleSpace]
toolBar.sizeToFit()
textField.inputAccessoryView = toolBar
}
func addTextField() {
func addInputAccessoryView() {
let width = UIScreen.main.bounds.width
let toolBar = UIToolbar(frame: CGRect(origin: .zero, size: CGSize(width: width, height: 48)))
toolBar.barStyle = .blackTranslucent
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(keyboardDoneButtonTapped))
done.tintColor = .lightGray
toolBar.items = [done, flexibleSpace]
toolBar.sizeToFit()
textField.inputAccessoryView = toolBar
}
textField.backgroundColor = .clear
textField.layer.cornerRadius = 3
textField.textAlignment = .center
@@ -487,14 +509,13 @@ private extension Renderer {
@objc func keyboardDoneButtonTapped() {
textField.endEditing(true)
guard let circularSlider = circularSlider else { return }
guard let text = textField.text, let newValue = Int(text) else {
updateText()
updateText(with: circularSlider.value, isPercentage: true)
return
}
circularSlider?.value = CGFloat(newValue)
circularSlider?.sendActions(for: .editingDidEnd)
//maxiDotView.setNeedsLayout()
circularSlider.setValue(Float(newValue))
maxiDotView.layoutSubviews()
}
// MARK: - Updates
@@ -524,28 +545,20 @@ private extension Renderer {
textField.isHidden = textFieldIsHidden
}
func updateText() {
guard let circularSlider = circularSlider else { return }
let minimum = Float(circularSlider.minimumValue)
let maximum = Float(circularSlider.maximumValue)
let _value = Float(circularSlider.value)
var decimalPlaces = circularSlider.labelDecimalPlaces
if value != 0 && _value.rounded(.towardZero) == 0 && decimalPlaces == 0 {
decimalPlaces = 2
func updateText(with newValue: Float, isPercentage: Bool = true) {
var value = Int(newValue)
if isPercentage {
// convert value (0...1) to a value within proposed range
value = Int(newValue * (maximumValue - minimumValue) + minimumValue)
}
guard let newValue = Float(String(format: "%.\(decimalPlaces)f", _value)) else { return }
switch newValue {
case minimum: textField.text = "MIN"
case maximum: textField.text = "MAX"
default: textField.text = String(format: "%.\(decimalPlaces)f", newValue)
switch value {
case Int(minimumValue): textField.text = "MIN"
case Int(maximumValue): textField.text = "MAX"
default: textField.text = "\(value)"
}
}
func updatePointerView(in bounds: CGRect) {
func updatePointerView(in bounds: CGRect, value: Float) {
let angleRange = angleDifferenceInDegree(from: startAngle.toDegree, to: endAngle.toDegree, isClockwise: isClockwise)
let angle = isClockwise ? startAngle.toDegree + (angleRange * CGFloat(value)) : startAngle.toDegree - (angleRange * CGFloat(value))
+57 -15
View File
@@ -78,20 +78,37 @@ class DotView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
var radius = (bounds.width/2) - dotRadius - dotInset
if let outerCircleRadius = outerCircleRadius {
radius = outerCircleRadius + dotRadius + dotInset
}
guard let sublayers = layer.sublayers else { return }
let radius = outerCircleRadius == nil ? (bounds.width/2) - dotRadius - dotInset : outerCircleRadius! + dotRadius + dotInset
for i in 0..<sublayers.count {
guard let dotLayer = sublayers[i] as? DotLayer else { continue }
if type == .mini && (i % dotCountPerSegment == 0) {
continue
}
let angle = startAngle + ((CGFloat(i) * unitAngle) * (isClockwise ? 1 : -1))
dotLayer.frame = CGRect(x: cos(angle) * radius - dotRadius,
y: sin(angle) * radius - dotRadius,
width: dotRadius * 2,
height: dotRadius * 2)
let x = cos(angle) * radius - dotRadius
let y = sin(angle) * radius - dotRadius
let width = dotRadius * 2
guard let dotLayer = sublayers[i] as? DotLayer else { continue }
dotLayer.frame = CGRect(x: x, y: y, width: width, height: width)
// switch type {
// case .mini:
// dotLayer.color = offColor
// dotLayer.highlightColor = highlightColor
// case .maxi:
// dotLayer.highlightColor = highlightColor
// if i <= currentIndex {
// dotLayer.color = (i >= dotCount - maxDotCount) ? maxColor : onColor
// } else {
// dotLayer.color = offColor
// }
// }
}
currentIndex = -1
updateColors(using: value)
@@ -103,22 +120,47 @@ class DotView: UIView {
}
func updateColors(using value: Float) {
guard type == .maxi else { return }
let index = Int(value * Float(dotCount - 1))
guard index != currentIndex else { return }
currentIndex = index
self.value = value
guard let sublayers = layer.sublayers else { return }
var hue: CGFloat = 0; var saturation: CGFloat = 0 ; var brightness: CGFloat = 0
var hue: CGFloat = 0
var saturation: CGFloat = 0
var brightness: CGFloat = 0
onColor.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil)
//print("first: \(hue)")
guard let sublayers = layer.sublayers else { return }
var j: CGFloat = 0
for i in 0..<sublayers.count {
guard let dotLayer = sublayers[i] as? DotLayer else { continue }
guard i <= currentIndex else { dotLayer.color = offColor; continue }
guard i >= dotCount - maxDotCount else { dotLayer.color = onColor; continue }
let newHue = hue > 0.5 ? hue + (j * ((1.0 - hue)/CGFloat(maxDotCount-1))) : hue - (j * (hue/CGFloat(maxDotCount-1)))
dotLayer.color = UIColor(hue: newHue , saturation: saturation, brightness: brightness, alpha: 1)
j += 1.0
if i <= currentIndex {
if i >= dotCount - maxDotCount {
var newHue: CGFloat
if hue > 0.5 {
newHue = hue + (j * ((1.0 - hue)/CGFloat(maxDotCount-1)))
} else {
newHue = hue - (j * (hue/CGFloat(maxDotCount-1)))
}
j += 1.0
//print("new: \(newHue)")
let newMaxColor = UIColor(hue: newHue , saturation: saturation, brightness: brightness, alpha: 1)
dotLayer.color = newMaxColor
}
else {
dotLayer.color = onColor
}
//dotLayer.color = (i >= dotCount - maxDotCount) ? maxColor : onColor
}
else {
dotLayer.color = offColor
}
}
}
}
+8 -7
View File
@@ -24,13 +24,6 @@ extension FloatingPoint {
let degree = self * 180 / .pi
return degree >= 0 ? degree : 360 + degree
}
public func roundedDown(toPlaces places: Int) -> Self {
let rounded = self.rounded(.down)
let power = Self(Int(powf(10, Float(places))))
let decimal = ((self - rounded) * power).rounded(.down)
return rounded + (decimal / power)
}
}
extension CGPoint {
@@ -60,3 +53,11 @@ extension CALayer {
return UIBezierPath(ovalIn: bounds.insetBy(dx: bounds.width * multiplier, dy: bounds.height * multiplier))
}
}
extension UIView {
func circlePath(with multiplier: CGFloat) -> UIBezierPath {
let multiplier = (1 - max(0, min(multiplier, 1))) / 2.0
return UIBezierPath(ovalIn: bounds.insetBy(dx: bounds.width * multiplier, dy: bounds.height * multiplier))
}
}
+5 -2
View File
@@ -66,7 +66,7 @@ class KnobView: UIView {
}
middleCircle.multiplier = middleCircleMultiplier
glowCircleLayer.multiplier = middleCircleMultiplier
middleCircleShadow.path = layer.circlePath(with: middleCircleMultiplier).cgPath
middleCircleShadow.path = circlePath(with: middleCircleMultiplier).cgPath
}
}
var innerCircleMultiplier: CGFloat = Constants.innerMultiplier {
@@ -148,7 +148,7 @@ class KnobView: UIView {
middleCircle.frame = bounds
innerCircle.frame = bounds
middleCircleShadow.path = layer.circlePath(with: middleCircleMultiplier).cgPath
middleCircleShadow.path = circlePath(with: middleCircleMultiplier).cgPath
glowCircleLayer.frame = bounds
}
@@ -163,6 +163,9 @@ class KnobView: UIView {
layer.insertSublayer(glowCircleLayer, above: outerCircle)
layer.insertSublayer(middleCircleShadow, above: glowCircleLayer)
layer.insertSublayer(middleCircle, above: middleCircleShadow)
// layer.insertSublayer(middleCircleShadow, above: outerCircle)
// layer.insertSublayer(glowCircleLayer, above: middleCircleShadow)
// layer.insertSublayer(middleCircle, above: glowCircleLayer)
layer.insertSublayer(innerCircle, above: middleCircle)
}
+14 -63
View File
@@ -1,25 +1,26 @@
![](https://raw.githubusercontent.com/ouraigua/JOCircularSlider/master/Screenshots/banner.gif)
# JOCircularSlider
[![Version](https://img.shields.io/cocoapods/v/JOCircularSlider.svg?style=flat)](https://cocoapods.org/pods/JOCircularSlider)
[![License](https://img.shields.io/cocoapods/l/JOCircularSlider.svg?style=flat)](https://cocoapods.org/pods/JOCircularSlider)
[![Platform](https://img.shields.io/cocoapods/p/JOCircularSlider.svg?style=flat)](https://cocoapods.org/pods/JOCircularSlider)
[![Language](https://img.shields.io/badge/language-Swift-orange.svg?style=flat)]()
[![License](https://img.shields.io/cocoapods/l/JOCircularSlider.svg?style=flat)](https://cocoapods.org/pods/JOCircularSlider)
[![Twitter: @ouraigua](https://img.shields.io/badge/twitter-@ouraigua-blue.svg?style=flat)](https://twitter.com/ouraigua)
[![Twitter: @ouraigua](https://img.shields.io/badge/contact-@ouraigua-blue.svg?style=flat)](https://twitter.com/ouraigua)
[![Readme Score](http://readme-score-api.herokuapp.com/score.svg?url=https://github.com/ouraigua/jocircularslider)](http://clayallsopp.github.io/readme-score?url=https://github.com/ouraigua/jocircularslider)
[![codebeat badge](https://codebeat.co/badges/c4db03f5-903a-4b0e-84bb-98362fc5bd7a)](https://codebeat.co/projects/github-com-ouraigua-jocircularslider-master)
# JOCircularSlider
## Overview
JOCircularSlider is a highly customisable and reusable iOS circular slider that mimics the behaviour of a knob control.
It uses no preset images and every one of its components is drawn completely in code making it extremely adaptable to every design and theme.
## Example
To run the example project, clone the repo, and run `pod install` from the Example directory first.
![](https://raw.githubusercontent.com/ouraigua/JOCircularSlider/master/Screenshots/shot1.gif)
![](https://raw.githubusercontent.com/ouraigua/JOCircularSlider/master/Screenshots/shot2.gif)
![](https://raw.githubusercontent.com/ouraigua/JOCircularSlider/master/Screenshots/shot3.gif)
![](https://github.com/ouraigua/JOCircularSlider/blob/master/Screenshots/shot1.gif)
![](https://github.com/ouraigua/JOCircularSlider/blob/master/Screenshots/shot2.gif)
![](https://github.com/ouraigua/JOCircularSlider/blob/master/Screenshots/shot3.gif)
## Requirements
@@ -38,16 +39,19 @@ pod 'JOCircularSlider'
## Usage
1. Visually:
```swift
import JOCircularSlider
```
Drag a UIView to your storyboard, change its class of to CircularSlider and start visually customising the design to your liking.
All the parameters are IBInspectable, so you can configure the slider straight from the attribute inspector tab, without having to write a single line of code.
![](https://raw.githubusercontent.com/ouraigua/JOCircularSlider/master/Screenshots/shot4.gif)
![](https://github.com/ouraigua/JOCircularSlider/blob/master/Screenshots/shot4.gif)
2. Programatically:
```swift
import JOCircularSlider
import JOCircularSlider
let circularSlider = CircularSlider(frame: aFrame)
circularSlider.startAngle = 230
circularSlider.endAngle = 310
@@ -57,60 +61,6 @@ circularSlider.isClockwise = false
```
These are just few of the many params you can configure for the slider.
The slider's min/max values are IBInspectable and default to 0.0 and 100.0 respectively.
They also support negative and positive values or a mixture of them.
```swift
@IBInspectable open var minimumValue: CGFloat = 0
@IBInspectable open var maximumValue: CGFloat = 100
```
The slider's `value` property is both { get set } and it is designed to work similarly to the familiar value property of UIKit's generic UISlider.
```swift
/**
This value will be pinned to minimumValue/maximumValue
The default value of this property is 0.0.
*/
@IBInspectable open var value: CGFloat // { get set }
```
In order to get value change notifications, use the `Target-Action` pattern which is an inherent part of UIControl, like so:
``` swift
/**
Add target/action for particular event.
- parameter target: The object whose action method is called
- parameter action: A selector identifying the action method to be called
- parameter Event: The control-specific events for which the action method is called
So far I've only implemented the following:
UIControl.Event.valueChanged
UIControl.Event.editingDidBegin
UIControl.Event.editingDidEnd
*/
circularSlider.addTarget(target: Any?, action: Selector, for: UIControl.Event)
```
To Control the appearance of the label displaying the value, use these:
```swift
open func setLabelFont(named: String, textColor: UIColor, multiplier: CGFloat)
open func setLabelShadow(color: UIColor, opacity: Float = 1, offset: CGSize = CGSize(width: 1, height: 1), radius: CGFloat = 0)
```
You can also specify the number of decimal places this label should show.
The default is 0.0 unless for example the value is within [0.0, 1.0]
```swift
@IBInspectable open var labelDecimalPlaces: Int = 0
```
If you need to override the text in the label, then just implement the following function inside the selector of the `Target-Action`
method for the event `UIControl.Event.valueChanged`
```swift
open func setLabelText(_ text: String?)
```
## References
The project is Inspired by:
@@ -124,3 +74,4 @@ Jalal Ouraigua, ouraigua@icloud.com
## License
JOCircularSlider is available under the MIT license. See the LICENSE file for more info.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB