Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1490573852 | |||
| 68f31bfa1f | |||
| 6086b3bad3 | |||
| 42dbab3b89 | |||
| c234281a9e | |||
| 070d2615c3 | |||
| 4206b108a9 | |||
| 9596434dca | |||
| 539be74ce8 | |||
| 70fa6d1acd | |||
| eb527c3621 | |||
| b1e0e3dca1 |
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"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]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
jazzy --podspec JOCircularSlider.podspec
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [1.0.3](https://github.com/ouraigua/JOCircularSlider/releases/tag/1.0.3)
|
||||
|
||||
* Add example
|
||||
|
||||
|
||||
## [1.0.0](https://github.com/ouraigua/JOCircularSlider/releases/tag/1.0.0)
|
||||
|
||||
* Initial release.
|
||||
@@ -11,12 +11,17 @@
|
||||
607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; };
|
||||
607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; };
|
||||
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
|
||||
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
|
||||
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
|
||||
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 */
|
||||
@@ -36,8 +41,6 @@
|
||||
607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||
607FACE51AFB9204008FA782 /* JOCircularSlider_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JOCircularSlider_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
|
||||
@@ -46,8 +49,15 @@
|
||||
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>"; };
|
||||
@@ -121,9 +131,9 @@
|
||||
607FACD71AFB9204008FA782 /* ViewController.swift */,
|
||||
AF737E2321B89B2B00BFBE5E /* GradientView.swift */,
|
||||
AF737E2521B89F8000BFBE5E /* Utils.swift */,
|
||||
AF737E2A21B8D71900BFBE5E /* Assets.xcassets */,
|
||||
607FACD91AFB9204008FA782 /* Main.storyboard */,
|
||||
607FACDC1AFB9204008FA782 /* Images.xcassets */,
|
||||
607FACDE1AFB9204008FA782 /* LaunchScreen.xib */,
|
||||
AF737E2721B8D60400BFBE5E /* LaunchScreen.storyboard */,
|
||||
607FACD31AFB9204008FA782 /* Supporting Files */,
|
||||
);
|
||||
name = "Example for JOCircularSlider";
|
||||
@@ -161,6 +171,11 @@
|
||||
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>";
|
||||
@@ -253,9 +268,14 @@
|
||||
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 */,
|
||||
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */,
|
||||
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */,
|
||||
AF4F276921BB942500D39C60 /* .jazzy_cmd.yaml in Resources */,
|
||||
AFB6605421BB1F2000E22629 /* .codebeatsettings in Resources */,
|
||||
AFB6605821BB1F3300E22629 /* .swift-version in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -364,12 +384,12 @@
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = {
|
||||
AF737E2721B8D60400BFBE5E /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
607FACDF1AFB9204008FA782 /* Base */,
|
||||
AF737E2821B8D60400BFBE5E /* Base */,
|
||||
);
|
||||
name = LaunchScreen.xib;
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1000"
|
||||
LastUpgradeVersion = "1010"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
+46
-1
@@ -40,6 +40,51 @@
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "20x20",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "83.5x83.5",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ios-marketing",
|
||||
"size" : "1024x1024",
|
||||
@@ -50,4 +95,4 @@
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="kyC-50-ACg">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<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>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="QKt-mf-1VZ">
|
||||
<objects>
|
||||
<viewController id="kyC-50-ACg" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="txe-SZ-eyi">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<viewLayoutGuide key="safeArea" id="esi-0o-8Hw"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="U0S-aT-UUb" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-346" y="-28"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 CocoaPods. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="JOCircularSlider" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="548" y="455"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<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">
|
||||
<device id="retina6_1" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
|
||||
<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.15235996039999999" green="0.17974209029999999" blue="0.22156283139999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="value" red="0.15294117647058825" green="0.1803921568627451" blue="0.2196078431372549" 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.13288810049999999" green="0.14611955109999999" blue="0.1740877602" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="value" red="0.13333333333333333" green="0.14509803921568626" blue="0.17254901960784313" 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.33810979099999999" green="0.36411823659999998" blue="0.42480460930000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="value" red="0.33725490196078434" green="0.36470588235294116" blue="0.42352941176470588" 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.2530443235" green="0.27250927159999999" blue="0.31792748339999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="value" red="0.25490196078431371" green="0.27058823529411763" blue="0.31764705882352939" 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.86000001430511475" 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.85999999999999999" 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.10980392160000001" green="0.12941176469999999" blue="0.15686274510000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="value" red="0.10980392156862745" green="0.12941176470588234" blue="0.15686274509803921" 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"/>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<string>2.0.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
@@ -30,6 +30,8 @@
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UIStatusBarStyle</key>
|
||||
<string>UIStatusBarStyleLightContent</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
@@ -38,5 +40,7 @@
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -11,7 +11,14 @@ import JOCircularSlider
|
||||
|
||||
class ViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var circularSlider: CircularSlider!
|
||||
@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 stackView: UIStackView!
|
||||
@IBOutlet weak var widthConstraint: NSLayoutConstraint! {
|
||||
didSet {
|
||||
@@ -49,11 +56,12 @@ class ViewController: UIViewController {
|
||||
let darkColor = UIColor(red: 86/255.0, green: 93/255.0, blue: 108/255.0, alpha: 1)
|
||||
let lightColor = UIColor(red: 136/255.0, green: 143/255.0, blue: 160/255.0, alpha: 1)
|
||||
let sliderDark = UIColor(red: 52/255.0, green: 60/255.0, blue: 72/255.0, alpha: 1)
|
||||
let sliderLight = UIColor(red: 128/255.0, green: 136/255.0, blue: 149/255.0, alpha: 1)
|
||||
|
||||
for subview in stackView.subviews {
|
||||
|
||||
if let slider = subview as? UISlider {
|
||||
slider.tintColor = theme == .dark ? sliderDark : .white
|
||||
slider.tintColor = theme == .dark ? sliderDark : sliderLight
|
||||
slider.maximumTrackTintColor = theme == .dark ? .black : UIColor.white.withAlphaComponent(0.4)
|
||||
|
||||
} else {
|
||||
@@ -70,7 +78,8 @@ class ViewController: UIViewController {
|
||||
circularSlider.startAngle = direction.startAngle
|
||||
circularSlider.endAngle = direction.endAngle
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.circularSlider.setValue(self.circularSlider.value, isPercentage: true)
|
||||
let value = self.circularSlider.value
|
||||
self.circularSlider.value = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +112,8 @@ class ViewController: UIViewController {
|
||||
circularSlider.knobMiddleCircleMultiplier = newMultiplier
|
||||
}
|
||||
|
||||
circularSlider.setValue(circularSlider.value, isPercentage: true)
|
||||
|
||||
let value = circularSlider.value
|
||||
circularSlider.value = value
|
||||
}
|
||||
|
||||
@IBAction private func changeDotCount(_ sender: UISlider) {
|
||||
@@ -116,6 +125,23 @@ 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))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -335,7 +335,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0930;
|
||||
LastUpgradeCheck = 0930;
|
||||
LastUpgradeCheck = 1010;
|
||||
};
|
||||
buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
@@ -559,6 +559,7 @@
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SYMROOT = "${SRCROOT}/../build";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
+20
-20
@@ -2,25 +2,25 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
+20
-20
@@ -2,25 +2,25 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
+20
-20
@@ -2,25 +2,25 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'JOCircularSlider'
|
||||
s.version = '1.0.0'
|
||||
s.summary = 'A highly customaizable and reusable circular slider for iOS applications.'
|
||||
s.version = '2.0.2'
|
||||
s.summary = 'A highly customisable and reusable iOS circular slider.'
|
||||
|
||||
# This description is used to generate tags and improve search results.
|
||||
# * Think: What does it do? Why did you write it? What is the focus?
|
||||
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
|
||||
# * Finally, don't worry about the indent, CocoaPods strips it!
|
||||
|
||||
s.description = <<-DESC
|
||||
A highly customaizable and reusable circular slider for iOS applications.
|
||||
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.
|
||||
It's written in Swift 4.2 and it's 100% IBDesignable and all parameters are IBInspectable.
|
||||
You can control almost every aspect of the slider's design: Size, colors, direction (clockwise/anti-clockwise), etc...
|
||||
DESC
|
||||
@@ -33,6 +33,8 @@ 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']
|
||||
|
||||
@@ -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 = UIColor(red: 206/255.0, green: 206/255.0, blue: 206/255.0, alpha: 1)
|
||||
public static let dotGrayColor = lightColor4
|
||||
public static let dotShadowOffset = CGSize(width: 2, height: 2)
|
||||
|
||||
public static let outerMultiplier : CGFloat = 0.86
|
||||
@@ -44,26 +44,22 @@ 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
|
||||
@@ -71,8 +67,7 @@ open class CircularSlider: UIControl {
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable
|
||||
open var highlightColor: UIColor {
|
||||
@IBInspectable open var highlightColor: UIColor {
|
||||
get { return renderer.knobView.highlightColor }
|
||||
set {
|
||||
renderer.knobView.highlightColor = newValue
|
||||
@@ -83,8 +78,7 @@ open class CircularSlider: UIControl {
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable
|
||||
open var knobOuterCircleMultiplier: CGFloat {
|
||||
@IBInspectable open var knobOuterCircleMultiplier: CGFloat {
|
||||
get { return renderer.knobView.outerCircleMultiplier }
|
||||
set {
|
||||
renderer.knobView.outerCircleMultiplier = newValue
|
||||
@@ -93,82 +87,69 @@ 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
|
||||
@@ -177,14 +158,12 @@ 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
|
||||
@@ -195,44 +174,37 @@ 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
|
||||
@@ -240,114 +212,78 @@ 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 }
|
||||
}
|
||||
|
||||
@IBInspectable
|
||||
open var minimumValue: CGFloat {
|
||||
get { return CGFloat(renderer.minimumValue) }
|
||||
/**
|
||||
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 }
|
||||
set {
|
||||
renderer.minimumValue = Float(newValue)
|
||||
setValue(value, isPercentage: true)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable
|
||||
open var maximumValue: CGFloat {
|
||||
get { return CGFloat(renderer.maximumValue) }
|
||||
set {
|
||||
renderer.maximumValue = Float(newValue)
|
||||
setValue(value, isPercentage: true)
|
||||
}
|
||||
}
|
||||
@IBInspectable open var minimumValue: CGFloat = 0
|
||||
|
||||
@IBInspectable
|
||||
open var startAngle: CGFloat {
|
||||
@IBInspectable open var maximumValue: CGFloat = 100
|
||||
|
||||
@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 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)
|
||||
setValue(renderer.minimumValue)
|
||||
value = minimumValue
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
setValue(renderer.minimumValue)
|
||||
value = minimumValue
|
||||
}
|
||||
|
||||
override open func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
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)
|
||||
renderer.updateUI(in: bounds)
|
||||
}
|
||||
|
||||
// MARK: - Touches
|
||||
@@ -358,6 +294,7 @@ 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?) {
|
||||
@@ -374,8 +311,30 @@ open class CircularSlider: UIControl {
|
||||
|
||||
let angelDeltaAsPercentage = Float(angelDelta / angleRange)
|
||||
guard abs(angelDeltaAsPercentage) < 1 else { return }
|
||||
let newValue = isClockwise ? value + angelDeltaAsPercentage : value - angelDeltaAsPercentage
|
||||
setValue(newValue, isPercentage: true)
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -418,9 +377,18 @@ class Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var minimumValue: Float = 0.0
|
||||
fileprivate var maximumValue: Float = 100.0
|
||||
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)
|
||||
|
||||
circularSlider?.sendActions(for: .valueChanged)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
@@ -429,8 +397,8 @@ class Renderer {
|
||||
commonInit()
|
||||
}
|
||||
|
||||
func update(_ bounds: CGRect, value: Float) {
|
||||
updatePointerView(in: bounds, value: value)
|
||||
func updateUI(in bounds: CGRect) {
|
||||
updatePointerView(in: bounds)
|
||||
updateTextField(in: bounds)
|
||||
updateDotViews(in: bounds)
|
||||
}
|
||||
@@ -460,32 +428,34 @@ private extension Renderer {
|
||||
circularSlider?.addSubview(knobView)
|
||||
knobView.translatesAutoresizingMaskIntoConstraints = false
|
||||
let views = ["view": knobView]
|
||||
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))
|
||||
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)
|
||||
}
|
||||
|
||||
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))
|
||||
toolBar.items = [done, flexibleSpace]
|
||||
toolBar.sizeToFit()
|
||||
textField.inputAccessoryView = toolBar
|
||||
}
|
||||
|
||||
textField.backgroundColor = .clear
|
||||
textField.layer.cornerRadius = 3
|
||||
textField.textAlignment = .center
|
||||
textField.text = ""
|
||||
textField.keyboardType = .numberPad
|
||||
textField.keyboardType = .numbersAndPunctuation
|
||||
textField.keyboardAppearance = .dark
|
||||
textField.clearsOnInsertion = true
|
||||
textField.adjustsFontSizeToFitWidth = true
|
||||
if let height = circularSlider?.bounds.height {
|
||||
@@ -507,13 +477,14 @@ 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(with: circularSlider.value, isPercentage: true)
|
||||
updateText()
|
||||
return
|
||||
}
|
||||
circularSlider.setValue(Float(newValue))
|
||||
maxiDotView.layoutSubviews()
|
||||
circularSlider?.value = CGFloat(newValue)
|
||||
circularSlider?.sendActions(for: .editingDidEnd)
|
||||
|
||||
//maxiDotView.setNeedsLayout()
|
||||
}
|
||||
|
||||
// MARK: - Updates
|
||||
@@ -543,20 +514,28 @@ private extension Renderer {
|
||||
textField.isHidden = textFieldIsHidden
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
}
|
||||
switch value {
|
||||
case Int(minimumValue): textField.text = "MIN"
|
||||
case Int(maximumValue): textField.text = "MAX"
|
||||
default: textField.text = "\(value)"
|
||||
|
||||
let newValue = _value.roundedDown(toPlaces: decimalPlaces)
|
||||
|
||||
switch newValue {
|
||||
case minimum: textField.text = "MIN"
|
||||
case maximum: textField.text = "MAX"
|
||||
default: textField.text = String(format: "%.\(decimalPlaces)f", newValue)
|
||||
}
|
||||
}
|
||||
|
||||
func updatePointerView(in bounds: CGRect, value: Float) {
|
||||
func updatePointerView(in bounds: CGRect) {
|
||||
|
||||
let angleRange = angleDifferenceInDegree(from: startAngle.toDegree, to: endAngle.toDegree, isClockwise: isClockwise)
|
||||
let angle = isClockwise ? startAngle.toDegree + (angleRange * CGFloat(value)) : startAngle.toDegree - (angleRange * CGFloat(value))
|
||||
|
||||
@@ -78,37 +78,20 @@ 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))
|
||||
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
|
||||
// }
|
||||
// }
|
||||
dotLayer.frame = CGRect(x: cos(angle) * radius - dotRadius,
|
||||
y: sin(angle) * radius - dotRadius,
|
||||
width: dotRadius * 2,
|
||||
height: dotRadius * 2)
|
||||
}
|
||||
currentIndex = -1
|
||||
updateColors(using: value)
|
||||
@@ -120,47 +103,22 @@ 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
|
||||
|
||||
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 hue: CGFloat = 0; var saturation: CGFloat = 0 ; var brightness: CGFloat = 0
|
||||
onColor.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil)
|
||||
var j: CGFloat = 0
|
||||
for i in 0..<sublayers.count {
|
||||
guard let dotLayer = sublayers[i] as? DotLayer else { continue }
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@ 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 {
|
||||
@@ -53,11 +60,3 @@ 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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class KnobView: UIView {
|
||||
}
|
||||
middleCircle.multiplier = middleCircleMultiplier
|
||||
glowCircleLayer.multiplier = middleCircleMultiplier
|
||||
middleCircleShadow.path = circlePath(with: middleCircleMultiplier).cgPath
|
||||
middleCircleShadow.path = layer.circlePath(with: middleCircleMultiplier).cgPath
|
||||
}
|
||||
}
|
||||
var innerCircleMultiplier: CGFloat = Constants.innerMultiplier {
|
||||
@@ -102,7 +102,7 @@ class KnobView: UIView {
|
||||
}()
|
||||
|
||||
lazy private var glowCircleLayer: CircularLayer = {
|
||||
let layer = CircularLayer(colors: [.red, .blue], maskType: .stroke(width: 5))
|
||||
let layer = CircularLayer(colors: [onColor, onColor], maskType: .stroke(width: 5))
|
||||
layer.multiplier = middleCircleMultiplier
|
||||
return layer
|
||||
}()
|
||||
@@ -148,7 +148,7 @@ class KnobView: UIView {
|
||||
middleCircle.frame = bounds
|
||||
innerCircle.frame = bounds
|
||||
|
||||
middleCircleShadow.path = circlePath(with: middleCircleMultiplier).cgPath
|
||||
middleCircleShadow.path = layer.circlePath(with: middleCircleMultiplier).cgPath
|
||||
glowCircleLayer.frame = bounds
|
||||
|
||||
}
|
||||
@@ -163,9 +163,6 @@ 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)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
# JOCircularSlider
|
||||

|
||||
|
||||
[](https://cocoapods.org/pods/JOCircularSlider)
|
||||
[](https://cocoapods.org/pods/JOCircularSlider)
|
||||
[](https://cocoapods.org/pods/JOCircularSlider)
|
||||
[]()
|
||||
[](https://cocoapods.org/pods/JOCircularSlider)
|
||||
[](https://twitter.com/ouraigua)
|
||||
[](http://clayallsopp.github.io/readme-score?url=https://github.com/ouraigua/jocircularslider)
|
||||
[](https://codebeat.co/projects/github-com-ouraigua-jocircularslider-master)
|
||||
|
||||
## Overview
|
||||
|
||||
JOCircularSlider is a highly customaizable and reusable circular slider for iOS applications.
|
||||
# JOCircularSlider
|
||||
|
||||
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.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -32,26 +38,85 @@ 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 paramters are IBInspectable, so you can configure the slider straight from the attribute inspector tab, without having to write a single line of code.
|
||||
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.
|
||||
|
||||

|
||||
|
||||
2. Programatically:
|
||||
|
||||
```swift
|
||||
|
||||
import JOCircularSlider
|
||||
let circularSlider = CircularSlider(frame: .zero)
|
||||
|
||||
let circularSlider = CircularSlider(frame: aFrame)
|
||||
circularSlider.startAngle = 230
|
||||
circularSlider.endAngle = 310
|
||||
circularSlider.minimumValue = 0
|
||||
circularSlider.maximumValue = 60
|
||||
circularSlider.isClockwise = true
|
||||
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:
|
||||
- [How To Make a Custom Control Tutorial: A Reusable Knob](https://www.raywenderlich.com/5294-how-to-make-a-custom-control-tutorial-a-reusable-knob)
|
||||
- [HGCircularSlider](https://github.com/HamzaGhazouani/HGCircularSlider)
|
||||
|
||||
## Author
|
||||
|
||||
Jalal Ouraigua, ouraigua@icloud.com
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 570 KiB After Width: | Height: | Size: 722 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 598 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 835 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
Reference in New Issue
Block a user