6 Commits

Author SHA1 Message Date
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
29 changed files with 377 additions and 478 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
-11
View File
@@ -1,11 +0,0 @@
# 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,17 +11,12 @@
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 */
@@ -41,6 +36,8 @@
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>"; };
@@ -49,15 +46,8 @@
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>"; };
@@ -131,9 +121,9 @@
607FACD71AFB9204008FA782 /* ViewController.swift */,
AF737E2321B89B2B00BFBE5E /* GradientView.swift */,
AF737E2521B89F8000BFBE5E /* Utils.swift */,
AF737E2A21B8D71900BFBE5E /* Assets.xcassets */,
607FACD91AFB9204008FA782 /* Main.storyboard */,
AF737E2721B8D60400BFBE5E /* LaunchScreen.storyboard */,
607FACDC1AFB9204008FA782 /* Images.xcassets */,
607FACDE1AFB9204008FA782 /* LaunchScreen.xib */,
607FACD31AFB9204008FA782 /* Supporting Files */,
);
name = "Example for JOCircularSlider";
@@ -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 */,
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */,
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -384,12 +364,12 @@
name = Main.storyboard;
sourceTree = "<group>";
};
AF737E2721B8D60400BFBE5E /* LaunchScreen.storyboard */ = {
607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
AF737E2821B8D60400BFBE5E /* Base */,
607FACDF1AFB9204008FA782 /* Base */,
);
name = LaunchScreen.storyboard;
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -1,29 +0,0 @@
<?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>
@@ -0,0 +1,46 @@
<?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="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"/>
@@ -40,51 +40,6 @@
"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",
@@ -95,4 +50,4 @@
"version" : 1,
"author" : "xcode"
}
}
}
+1 -5
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.0.2</string>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
@@ -30,8 +30,6 @@
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
@@ -40,7 +38,5 @@
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
+5 -31
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 {
@@ -56,12 +49,11 @@ 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 : sliderLight
slider.tintColor = theme == .dark ? sliderDark : .white
slider.maximumTrackTintColor = theme == .dark ? .black : UIColor.white.withAlphaComponent(0.4)
} else {
@@ -78,8 +70,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 +103,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 +116,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;
+20 -20
View File
@@ -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>2.0.2</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>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -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>2.0.2</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>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
@@ -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>2.0.2</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>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
+3 -5
View File
@@ -8,8 +8,8 @@
Pod::Spec.new do |s|
s.name = 'JOCircularSlider'
s.version = '2.0.2'
s.summary = 'A highly customisable and reusable iOS circular slider.'
s.version = '1.0.0'
s.summary = 'A highly customaizable and reusable circular slider for iOS applications.'
# 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
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.
A highly customaizable and reusable circular slider for iOS applications.
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,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 -132
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,78 +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 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
@@ -294,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?) {
@@ -311,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)
}
}
@@ -377,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
@@ -397,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)
}
@@ -428,34 +460,32 @@ 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))
toolBar.items = [done, flexibleSpace]
toolBar.sizeToFit()
textField.inputAccessoryView = toolBar
}
textField.backgroundColor = .clear
textField.layer.cornerRadius = 3
textField.textAlignment = .center
textField.text = ""
textField.keyboardType = .numbersAndPunctuation
textField.keyboardAppearance = .dark
textField.keyboardType = .numberPad
textField.clearsOnInsertion = true
textField.adjustsFontSizeToFitWidth = true
if let height = circularSlider?.bounds.height {
@@ -477,14 +507,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
@@ -514,28 +543,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)
}
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)
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))
}
}
+6 -3
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 {
@@ -102,7 +102,7 @@ class KnobView: UIView {
}()
lazy private var glowCircleLayer: CircularLayer = {
let layer = CircularLayer(colors: [onColor, onColor], maskType: .stroke(width: 5))
let layer = CircularLayer(colors: [.red, .blue], maskType: .stroke(width: 5))
layer.multiplier = middleCircleMultiplier
return layer
}()
@@ -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)
}
+16 -81
View File
@@ -1,25 +1,19 @@
![](https://raw.githubusercontent.com/ouraigua/JOCircularSlider/master/Screenshots/banner.gif)
[![Version](https://img.shields.io/cocoapods/v/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)
[![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
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.
[![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)
## Overview
JOCircularSlider is a highly customaizable and reusable circular slider for iOS applications.
## 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)
![](/Screenshots/shot1.gif)
## Requirements
@@ -38,85 +32,26 @@ 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)
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.
2. Programatically:
```swift
import JOCircularSlider
let circularSlider = CircularSlider(frame: aFrame)
import JOCircularSlider
let circularSlider = CircularSlider(frame: .zero)
circularSlider.startAngle = 230
circularSlider.endAngle = 310
circularSlider.minimumValue = 0
circularSlider.maximumValue = 60
circularSlider.isClockwise = false
circularSlider.isClockwise = true
```
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.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 722 KiB

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 835 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB