Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a51611e086 | |||
| e593fcfdd3 | |||
| ccac563a6d | |||
| 05d7ea54b7 | |||
| 488603e406 | |||
| b2cdaaa095 | |||
| 84ea211cdd | |||
| 146bb5811f | |||
| a7ab1885e2 | |||
| 11099e4240 | |||
| 06f166642e | |||
| d095f0663c | |||
| 43c20d9a81 | |||
| 8bf2b40707 | |||
| ba525189fb | |||
| 86dbfc98d4 | |||
| 1a0b0b90e5 |
+1
-1
@@ -1 +1 @@
|
||||
3.0
|
||||
4.0
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3CFA1D9A21720FB70094F95E /* KDCircularProgress.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC6FF0C71D92FEA9002E6571 /* KDCircularProgress.framework */; };
|
||||
3CFA1D9B21720FB70094F95E /* KDCircularProgress.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BC6FF0C71D92FEA9002E6571 /* KDCircularProgress.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BC5B0C1D1D92F75600B43506 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5B0C1C1D92F75600B43506 /* AppDelegate.swift */; };
|
||||
BC5B0C1F1D92F75600B43506 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5B0C1E1D92F75600B43506 /* ViewController.swift */; };
|
||||
BC5B0C221D92F75600B43506 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BC5B0C201D92F75600B43506 /* Main.storyboard */; };
|
||||
@@ -15,6 +17,13 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
3CFA1D9C21720FB70094F95E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = BC5B0C2E1D92F76E00B43506 /* KDCircularProgress.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = BC5B0BE71D92F4FA00B43506;
|
||||
remoteInfo = "KDCircularProgress iOS";
|
||||
};
|
||||
BC6FF0C61D92FEA9002E6571 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = BC5B0C2E1D92F76E00B43506 /* KDCircularProgress.xcodeproj */;
|
||||
@@ -24,6 +33,20 @@
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
3CFA1D9E21720FB70094F95E /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
3CFA1D9B21720FB70094F95E /* KDCircularProgress.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
BC5B0C191D92F75600B43506 /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
BC5B0C1C1D92F75600B43506 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
@@ -40,6 +63,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3CFA1D9A21720FB70094F95E /* KDCircularProgress.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -94,10 +118,12 @@
|
||||
BC5B0C151D92F75600B43506 /* Sources */,
|
||||
BC5B0C161D92F75600B43506 /* Frameworks */,
|
||||
BC5B0C171D92F75600B43506 /* Resources */,
|
||||
3CFA1D9E21720FB70094F95E /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
3CFA1D9D21720FB70094F95E /* PBXTargetDependency */,
|
||||
);
|
||||
name = "iOS Example";
|
||||
productName = "iOS Example";
|
||||
@@ -111,18 +137,19 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0800;
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 1000;
|
||||
ORGANIZATIONNAME = "Kaan Dedeoglu";
|
||||
TargetAttributes = {
|
||||
BC5B0C181D92F75600B43506 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = BC5B0C141D92F75600B43506 /* Build configuration list for PBXProject "iOS Example" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
@@ -179,6 +206,14 @@
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
3CFA1D9D21720FB70094F95E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = "KDCircularProgress iOS";
|
||||
targetProxy = 3CFA1D9C21720FB70094F95E /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
BC5B0C201D92F75600B43506 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
@@ -208,15 +243,24 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -257,15 +301,24 @@
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -293,24 +346,28 @@
|
||||
BC5B0C2C1D92F75600B43506 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = "iOS Example/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.kaandedeoglu.KDCircularProgress.iOS-Example";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
BC5B0C2D1D92F75600B43506 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
INFOPLIST_FILE = "iOS Example/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.kaandedeoglu.KDCircularProgress.iOS-Example";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'KDCircularProgress'
|
||||
s.version = '1.5.2'
|
||||
s.version = '1.5.4'
|
||||
s.license = 'MIT'
|
||||
s.summary = 'A circular progress view with gradients written in Swift'
|
||||
s.homepage = 'https://github.com/kaandedeoglu/KDCircularProgress'
|
||||
s.authors = { 'Kaan Dedeoglu' => 'kaandedeoglu@me.com' }
|
||||
s.source = { :git => 'https://github.com/kaandedeoglu/KDCircularProgress.git', :tag => s.version }
|
||||
|
||||
s.ios.deployment_target = '8.0'
|
||||
s.ios.deployment_target = '9.0'
|
||||
|
||||
s.source_files = 'KDCircularProgress/*.swift'
|
||||
s.requires_arc = true
|
||||
|
||||
@@ -93,20 +93,22 @@
|
||||
BC5B0BD91D92F42D00B43506 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0800;
|
||||
LastUpgradeCheck = 1000;
|
||||
TargetAttributes = {
|
||||
BC5B0BE71D92F4FA00B43506 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
LastSwiftMigration = 1020;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = BC5B0BDC1D92F42D00B43506 /* Build configuration list for PBXProject "KDCircularProgress" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = BC5B0BD81D92F42D00B43506;
|
||||
productRefGroup = BC5B0BE91D92F4FA00B43506 /* Products */;
|
||||
@@ -143,14 +145,66 @@
|
||||
BC5B0BDD1D92F42D00B43506 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
BC5B0BDE1D92F42D00B43506 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@@ -177,7 +231,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
@@ -203,7 +257,6 @@
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = KDCircularProgress/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@@ -212,7 +265,7 @@
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
@@ -242,7 +295,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
@@ -262,7 +315,6 @@
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = KDCircularProgress/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = kaandedeoglu.KDCircularProgress;
|
||||
@@ -270,7 +322,7 @@
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0800"
|
||||
LastUpgradeVersion = "1000"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.5.2</string>
|
||||
<string>1.5.4</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// KDCircularProgress iOS.h
|
||||
// KDCircularProgress iOS
|
||||
//
|
||||
// Created by Kaan Dedeoglu on 9/21/16.
|
||||
// Copyright (c) 2019 Kaan Dedeoglu. All rights reserved.
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
@@ -2,103 +2,45 @@
|
||||
// KDCircularProgress.swift
|
||||
// KDCircularProgress
|
||||
//
|
||||
// Created by Kaan Dedeoglu on 1/14/15.
|
||||
// Copyright (c) 2015 Kaan Dedeoglu. All rights reserved.
|
||||
// Copyright (c) 2019 Kaan Dedeoglu. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public enum KDCircularProgressGlowMode {
|
||||
@objc public enum KDCircularProgressGlowMode: Int {
|
||||
case forward, reverse, constant, noGlow
|
||||
}
|
||||
|
||||
@IBDesignable
|
||||
@objcMembers
|
||||
public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
|
||||
private enum Conversion {
|
||||
static func degreesToRadians (value:CGFloat) -> CGFloat {
|
||||
return value * CGFloat.pi / 180.0
|
||||
}
|
||||
}
|
||||
|
||||
private enum Utility {
|
||||
static func clamp<T: Comparable>(value: T, minMax: (T, T)) -> T {
|
||||
let (min, max) = minMax
|
||||
if value < min {
|
||||
return min
|
||||
} else if value > max {
|
||||
return max
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
static func inverseLerp(value: CGFloat, minMax: (CGFloat, CGFloat)) -> CGFloat {
|
||||
return (value - minMax.0) / (minMax.1 - minMax.0)
|
||||
}
|
||||
|
||||
static func lerp(value: CGFloat, minMax: (CGFloat, CGFloat)) -> CGFloat {
|
||||
return (minMax.1 - minMax.0) * value + minMax.0
|
||||
}
|
||||
|
||||
static func colorLerp(value: CGFloat, minMax: (UIColor, UIColor)) -> UIColor {
|
||||
let clampedValue = clamp(value: value, minMax: (0, 1))
|
||||
|
||||
let zero = CGFloat(0)
|
||||
|
||||
var (r0, g0, b0, a0) = (zero, zero, zero, zero)
|
||||
minMax.0.getRed(&r0, green: &g0, blue: &b0, alpha: &a0)
|
||||
|
||||
var (r1, g1, b1, a1) = (zero, zero, zero, zero)
|
||||
minMax.1.getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
|
||||
|
||||
return UIColor(red: lerp(value: clampedValue, minMax: (r0, r1)), green: lerp(value: clampedValue, minMax: (g0, g1)), blue: lerp(value: clampedValue, minMax: (b0, b1)), alpha: lerp(value: clampedValue, minMax: (a0, a1)))
|
||||
}
|
||||
|
||||
static func mod(value: Double, range: Double, minMax: (Double, Double)) -> Double {
|
||||
let (min, max) = minMax
|
||||
assert(abs(range) <= abs(max - min), "range should be <= than the interval")
|
||||
if value >= min && value <= max {
|
||||
return value
|
||||
} else if value < min {
|
||||
return mod(value: value + range, range: range, minMax: minMax)
|
||||
} else {
|
||||
return mod(value: value - range, range: range, minMax: minMax)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var progressLayer: KDCircularProgressViewLayer {
|
||||
get {
|
||||
return layer as! KDCircularProgressViewLayer
|
||||
}
|
||||
}
|
||||
|
||||
private var radius: CGFloat = 0 {
|
||||
private var radius: CGFloat = 0.0 {
|
||||
didSet {
|
||||
progressLayer.radius = radius
|
||||
}
|
||||
}
|
||||
|
||||
public var progress: Double = 0 {
|
||||
didSet {
|
||||
let clampedProgress = Utility.clamp(value: progress, minMax: (0, 1))
|
||||
angle = 360 * clampedProgress
|
||||
}
|
||||
public var progress: Double {
|
||||
get { return angle.mod(between: 0.0, and: 360.0, byIncrementing: 360.0) / 360.0 }
|
||||
set { angle = newValue.clamp(lowerBound: 0.0, upperBound: 1.0) * 360.0 }
|
||||
}
|
||||
|
||||
@IBInspectable public var angle: Double = 0 {
|
||||
@IBInspectable public var angle: Double = 0.0 {
|
||||
didSet {
|
||||
if self.isAnimating() {
|
||||
self.pauseAnimation()
|
||||
}
|
||||
pauseIfAnimating()
|
||||
progressLayer.angle = angle
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var startAngle: Double = 0 {
|
||||
@IBInspectable public var startAngle: Double = 0.0 {
|
||||
didSet {
|
||||
startAngle = Utility.mod(value: startAngle, range: 360, minMax: (0, 360))
|
||||
startAngle = startAngle.mod(between: 0.0, and: 360.0, byIncrementing: 360.0)
|
||||
progressLayer.startAngle = startAngle
|
||||
progressLayer.setNeedsDisplay()
|
||||
}
|
||||
@@ -123,36 +65,36 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var gradientRotateSpeed: CGFloat = 0 {
|
||||
@IBInspectable public var gradientRotateSpeed: CGFloat = 0.0 {
|
||||
didSet {
|
||||
progressLayer.gradientRotateSpeed = gradientRotateSpeed
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var glowAmount: CGFloat = 1.0 {//Between 0 and 1
|
||||
@IBInspectable public var glowAmount: CGFloat = 1.0 {
|
||||
didSet {
|
||||
glowAmount = Utility.clamp(value: glowAmount, minMax: (0, 1))
|
||||
glowAmount = glowAmount.clamp(lowerBound: 0.0, upperBound: 1.0)
|
||||
progressLayer.glowAmount = glowAmount
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var glowMode: KDCircularProgressGlowMode = .forward {
|
||||
public var glowMode: KDCircularProgressGlowMode = .forward {
|
||||
didSet {
|
||||
progressLayer.glowMode = glowMode
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var progressThickness: CGFloat = 0.4 {//Between 0 and 1
|
||||
@IBInspectable public var progressThickness: CGFloat = 0.4 {
|
||||
didSet {
|
||||
progressThickness = Utility.clamp(value: progressThickness, minMax: (0, 1))
|
||||
progressLayer.progressThickness = progressThickness/2
|
||||
progressThickness = progressThickness.clamp(lowerBound: 0.0, upperBound: 1.0)
|
||||
progressLayer.progressThickness = progressThickness / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var trackThickness: CGFloat = 0.5 {//Between 0 and 1
|
||||
didSet {
|
||||
trackThickness = Utility.clamp(value: trackThickness, minMax: (0, 1))
|
||||
progressLayer.trackThickness = trackThickness/2
|
||||
trackThickness = trackThickness.clamp(lowerBound: 0.0, upperBound: 1.0)
|
||||
progressLayer.trackThickness = trackThickness / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,13 +112,8 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
|
||||
public var progressColors: [UIColor] {
|
||||
get {
|
||||
return progressLayer.colorsArray
|
||||
}
|
||||
|
||||
set {
|
||||
set(colors: newValue)
|
||||
}
|
||||
get { return progressLayer.colorsArray }
|
||||
set { set(colors: newValue) }
|
||||
}
|
||||
|
||||
//These are used only from the Interface-Builder. Changing these from code will have no effect.
|
||||
@@ -191,7 +128,6 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
super.init(frame: frame)
|
||||
setInitialValues()
|
||||
refreshValues()
|
||||
checkAndSetIBColors()
|
||||
}
|
||||
|
||||
convenience public init(frame:CGRect, colors: UIColor...) {
|
||||
@@ -199,8 +135,8 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
set(colors: colors)
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)!
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
setInitialValues()
|
||||
refreshValues()
|
||||
@@ -216,11 +152,11 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
|
||||
public override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
radius = (frame.size.width/2.0) * 0.8
|
||||
radius = (frame.size.width / 2.0) * 0.8
|
||||
}
|
||||
|
||||
private func setInitialValues() {
|
||||
radius = (frame.size.width/2.0) * 0.8 //We always apply a 20% padding, stopping glows from being clipped
|
||||
radius = (frame.size.width / 2.0) * 0.8 //We always apply a 20% padding, stopping glows from being clipped
|
||||
backgroundColor = .clear
|
||||
set(colors: .white, .cyan)
|
||||
}
|
||||
@@ -234,15 +170,15 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
progressLayer.gradientRotateSpeed = gradientRotateSpeed
|
||||
progressLayer.glowAmount = glowAmount
|
||||
progressLayer.glowMode = glowMode
|
||||
progressLayer.progressThickness = progressThickness/2
|
||||
progressLayer.progressThickness = progressThickness / 2.0
|
||||
progressLayer.trackColor = trackColor
|
||||
progressLayer.trackThickness = trackThickness/2
|
||||
progressLayer.trackThickness = trackThickness / 2.0
|
||||
}
|
||||
|
||||
private func checkAndSetIBColors() {
|
||||
let nonNilColors = [IBColor1, IBColor2, IBColor3].flatMap { $0 }
|
||||
if !nonNilColors.isEmpty {
|
||||
set(colors: nonNilColors)
|
||||
let IBColors = [IBColor1, IBColor2, IBColor3].compactMap { $0 }
|
||||
if IBColors.isEmpty == false {
|
||||
set(colors: IBColors)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,20 +192,17 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
|
||||
public func animate(fromAngle: Double, toAngle: Double, duration: TimeInterval, relativeDuration: Bool = true, completion: ((Bool) -> Void)?) {
|
||||
if isAnimating() {
|
||||
pauseAnimation()
|
||||
}
|
||||
|
||||
pauseIfAnimating()
|
||||
let animationDuration: TimeInterval
|
||||
if relativeDuration {
|
||||
animationDuration = duration
|
||||
} else {
|
||||
let traveledAngle = Utility.mod(value: toAngle - fromAngle, range: 360, minMax: (0, 360))
|
||||
let scaledDuration = (TimeInterval(traveledAngle) * duration) / 360
|
||||
let traveledAngle = (toAngle - fromAngle).mod(between: 0.0, and: 360.0, byIncrementing: 360.0)
|
||||
let scaledDuration = TimeInterval(traveledAngle) * duration / 360.0
|
||||
animationDuration = scaledDuration
|
||||
}
|
||||
|
||||
let animation = CABasicAnimation(keyPath: "angle")
|
||||
let animation = CABasicAnimation(keyPath: #keyPath(KDCircularProgressViewLayer.angle))
|
||||
animation.fromValue = fromAngle
|
||||
animation.toValue = toAngle
|
||||
animation.duration = animationDuration
|
||||
@@ -282,9 +215,7 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
|
||||
public func animate(toAngle: Double, duration: TimeInterval, relativeDuration: Bool = true, completion: ((Bool) -> Void)?) {
|
||||
if isAnimating() {
|
||||
pauseAnimation()
|
||||
}
|
||||
pauseIfAnimating()
|
||||
animate(fromAngle: angle, toAngle: toAngle, duration: duration, relativeDuration: relativeDuration, completion: completion)
|
||||
}
|
||||
|
||||
@@ -296,6 +227,12 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
angle = currentValue
|
||||
}
|
||||
|
||||
private func pauseIfAnimating() {
|
||||
if isAnimating() {
|
||||
pauseAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
public func stopAnimation() {
|
||||
progressLayer.removeAllAnimations()
|
||||
angle = 0
|
||||
@@ -306,21 +243,17 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
|
||||
public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
|
||||
if let completionBlock = animationCompletionBlock {
|
||||
animationCompletionBlock = nil
|
||||
completionBlock(flag)
|
||||
}
|
||||
animationCompletionBlock?(flag)
|
||||
animationCompletionBlock = nil
|
||||
}
|
||||
|
||||
public override func didMoveToWindow() {
|
||||
if let window = window {
|
||||
progressLayer.contentsScale = window.screen.scale
|
||||
}
|
||||
window.map { progressLayer.contentsScale = $0.screen.scale }
|
||||
}
|
||||
|
||||
public override func willMove(toSuperview newSuperview: UIView?) {
|
||||
if newSuperview == nil && isAnimating() {
|
||||
pauseAnimation()
|
||||
if newSuperview == nil {
|
||||
pauseIfAnimating()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,12 +266,10 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
|
||||
private class KDCircularProgressViewLayer: CALayer {
|
||||
@NSManaged var angle: Double
|
||||
var radius: CGFloat = 0 {
|
||||
didSet {
|
||||
invalidateGradientCache()
|
||||
}
|
||||
var radius: CGFloat = 0.0 {
|
||||
didSet { invalidateGradientCache() }
|
||||
}
|
||||
var startAngle: Double = 0
|
||||
var startAngle: Double = 0.0
|
||||
var clockwise: Bool = true {
|
||||
didSet {
|
||||
if clockwise != oldValue {
|
||||
@@ -348,21 +279,17 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
var roundedCorners: Bool = true
|
||||
var lerpColorMode: Bool = false
|
||||
var gradientRotateSpeed: CGFloat = 0 {
|
||||
didSet {
|
||||
invalidateGradientCache()
|
||||
}
|
||||
var gradientRotateSpeed: CGFloat = 0.0 {
|
||||
didSet { invalidateGradientCache() }
|
||||
}
|
||||
var glowAmount: CGFloat = 0
|
||||
var glowAmount: CGFloat = 0.0
|
||||
var glowMode: KDCircularProgressGlowMode = .forward
|
||||
var progressThickness: CGFloat = 0.5
|
||||
var trackThickness: CGFloat = 0.5
|
||||
var trackColor: UIColor = .black
|
||||
var progressInsideFillColor: UIColor = .clear
|
||||
var colorsArray: [UIColor] = [] {
|
||||
didSet {
|
||||
invalidateGradientCache()
|
||||
}
|
||||
didSet { invalidateGradientCache() }
|
||||
}
|
||||
private var gradientCache: CGGradient?
|
||||
private var locationsCache: [CGFloat]?
|
||||
@@ -374,9 +301,9 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
case .forward:
|
||||
return CGFloat(angle) * size * sizeToGlowRatio * glowAmount
|
||||
case .reverse:
|
||||
return CGFloat(360 - angle) * size * sizeToGlowRatio * glowAmount
|
||||
return CGFloat(360.0 - angle) * size * sizeToGlowRatio * glowAmount
|
||||
case .constant:
|
||||
return 360 * size * sizeToGlowRatio * glowAmount
|
||||
return 360.0 * size * sizeToGlowRatio * glowAmount
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
@@ -384,7 +311,10 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
|
||||
override class func needsDisplay(forKey key: String) -> Bool {
|
||||
return key == "angle" ? true : super.needsDisplay(forKey: key)
|
||||
if key == #keyPath(angle) {
|
||||
return true
|
||||
}
|
||||
return super.needsDisplay(forKey: key)
|
||||
}
|
||||
|
||||
override init(layer: Any) {
|
||||
@@ -423,9 +353,12 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
|
||||
let trackLineWidth = radius * trackThickness
|
||||
let progressLineWidth = radius * progressThickness
|
||||
let arcRadius = max(radius - trackLineWidth/2, radius - progressLineWidth/2)
|
||||
ctx.addArc(center: CGPoint(x: width/2.0, y: height/2.0), radius: arcRadius, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: false)
|
||||
trackColor.set()
|
||||
let arcRadius = max(radius - trackLineWidth / 2.0, radius - progressLineWidth / 2.0)
|
||||
ctx.addArc(center: CGPoint(x: width / 2.0, y: height / 2.0),
|
||||
radius: arcRadius,
|
||||
startAngle: 0,
|
||||
endAngle: CGFloat.pi * 2,
|
||||
clockwise: false)
|
||||
ctx.setStrokeColor(trackColor.cgColor)
|
||||
ctx.setFillColor(progressInsideFillColor.cgColor)
|
||||
ctx.setLineWidth(trackLineWidth)
|
||||
@@ -435,18 +368,27 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
|
||||
|
||||
let imageCtx = UIGraphicsGetCurrentContext()
|
||||
let reducedAngle = Utility.mod(value: angle, range: 360, minMax: (0, 360))
|
||||
let fromAngle = Conversion.degreesToRadians(value: CGFloat(-startAngle))
|
||||
let toAngle = Conversion.degreesToRadians(value: CGFloat((clockwise == true ? -reducedAngle : reducedAngle) - startAngle))
|
||||
|
||||
imageCtx?.addArc(center: CGPoint(x: width/2.0, y: height/2.0), radius: arcRadius, startAngle: fromAngle, endAngle: toAngle, clockwise: clockwise)
|
||||
|
||||
let glowValue = GlowConstants.glowAmount(forAngle: reducedAngle, glowAmount: glowAmount, glowMode: glowMode, size: width)
|
||||
if glowValue > 0 {
|
||||
imageCtx?.setShadow(offset: CGSize.zero, blur: glowValue, color: UIColor.black.cgColor)
|
||||
let canonicalAngle = angle.mod(between: 0.0, and: 360.0, byIncrementing: 360.0)
|
||||
let fromAngle = -startAngle.radians
|
||||
let toAngle: Double
|
||||
if clockwise {
|
||||
toAngle = (-canonicalAngle - startAngle).radians
|
||||
} else {
|
||||
toAngle = (canonicalAngle - startAngle).radians
|
||||
}
|
||||
|
||||
let linecap: CGLineCap = roundedCorners == true ? .round : .butt
|
||||
imageCtx?.addArc(center: CGPoint(x: width / 2.0, y: height / 2.0),
|
||||
radius: arcRadius,
|
||||
startAngle: CGFloat(fromAngle),
|
||||
endAngle: CGFloat(toAngle),
|
||||
clockwise: clockwise)
|
||||
|
||||
let glowValue = GlowConstants.glowAmount(forAngle: canonicalAngle, glowAmount: glowAmount, glowMode: glowMode, size: width)
|
||||
if glowValue > 0 {
|
||||
imageCtx?.setShadow(offset: .zero, blur: glowValue, color: UIColor.black.cgColor)
|
||||
}
|
||||
|
||||
let linecap: CGLineCap = roundedCorners ? .round : .butt
|
||||
imageCtx?.setLineCap(linecap)
|
||||
imageCtx?.setLineWidth(progressLineWidth)
|
||||
imageCtx?.drawPath(using: .stroke)
|
||||
@@ -457,80 +399,61 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
ctx.saveGState()
|
||||
ctx.clip(to: bounds, mask: drawMask)
|
||||
|
||||
//Gradient - Fill
|
||||
if !lerpColorMode && colorsArray.count > 1 {
|
||||
let rgbColorsArray: [UIColor] = colorsArray.map { color in // Make sure every color in colors array is in RGB color space
|
||||
if color.cgColor.numberOfComponents == 2 {
|
||||
if let whiteValue = color.cgColor.components?[0] {
|
||||
return UIColor(red: whiteValue, green: whiteValue, blue: whiteValue, alpha: 1.0)
|
||||
} else {
|
||||
return UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
|
||||
}
|
||||
} else {
|
||||
return color
|
||||
}
|
||||
}
|
||||
|
||||
let componentsArray = rgbColorsArray.flatMap { color -> [CGFloat] in
|
||||
guard let components = color.cgColor.components else { return [] }
|
||||
return [components[0], components[1], components[2], 1.0]
|
||||
}
|
||||
|
||||
drawGradientWith(context: ctx, componentsArray: componentsArray)
|
||||
if colorsArray.isEmpty {
|
||||
fillRect(withContext: ctx, color: .white)
|
||||
} else if colorsArray.count == 1 {
|
||||
fillRect(withContext: ctx, color: colorsArray[0])
|
||||
} else if lerpColorMode {
|
||||
lerp(withContext: ctx, colorsArray: colorsArray)
|
||||
} else {
|
||||
var color: UIColor?
|
||||
if colorsArray.isEmpty {
|
||||
color = UIColor.white
|
||||
} else if colorsArray.count == 1 {
|
||||
color = colorsArray[0]
|
||||
} else {
|
||||
// lerpColorMode is true
|
||||
let t = CGFloat(reducedAngle) / 360
|
||||
let steps = colorsArray.count - 1
|
||||
let step = 1 / CGFloat(steps)
|
||||
for i in 1...steps {
|
||||
let fi = CGFloat(i)
|
||||
if (t <= fi * step || i == steps) {
|
||||
let colorT = Utility.inverseLerp(value: t, minMax: ((fi - 1) * step, fi * step))
|
||||
color = Utility.colorLerp(value: colorT, minMax: (colorsArray[i - 1], colorsArray[i]))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let color = color {
|
||||
fillRectWith(context: ctx, color: color)
|
||||
}
|
||||
drawGradient(withContext: ctx, colorsArray: colorsArray)
|
||||
}
|
||||
|
||||
ctx.restoreGState()
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
|
||||
private func fillRectWith(context: CGContext!, color: UIColor) {
|
||||
private func lerp(withContext context: CGContext, colorsArray: [UIColor]) {
|
||||
let canonicalAngle = angle.mod(between: 0.0, and: 360.0, byIncrementing: 360.0)
|
||||
let percentage = canonicalAngle / 360.0
|
||||
let steps = colorsArray.count - 1
|
||||
let step = 1.0 / Double(steps)
|
||||
|
||||
for i in 1...steps {
|
||||
let di = Double(i)
|
||||
if percentage <= di * step || i == steps {
|
||||
let colorT = percentage.inverseLerp(min: (di - 1) * step, max: di * step)
|
||||
let color = colorT.colorLerp(minColor: colorsArray[i - 1], maxColor: colorsArray[i])
|
||||
fillRect(withContext: context, color: color)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func fillRect(withContext context: CGContext, color: UIColor) {
|
||||
context.setFillColor(color.cgColor)
|
||||
context.fill(bounds)
|
||||
}
|
||||
|
||||
private func drawGradientWith(context: CGContext!, componentsArray: [CGFloat]) {
|
||||
private func drawGradient(withContext context: CGContext, colorsArray: [UIColor]) {
|
||||
let baseSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let locations = locationsCache ?? gradientLocationsFor(colorCount: componentsArray.count/4, gradientWidth: bounds.size.width)
|
||||
let locations = locationsCache ?? gradientLocationsFor(colorCount: colorsArray.count, gradientWidth: bounds.size.width)
|
||||
let gradient: CGGradient
|
||||
|
||||
if let cachedGradient = gradientCache {
|
||||
gradient = cachedGradient
|
||||
} else {
|
||||
guard let cachedGradient = CGGradient(colorSpace: baseSpace, colorComponents: componentsArray, locations: locations, count: componentsArray.count/4) else {
|
||||
return
|
||||
}
|
||||
guard let newGradient = CGGradient(colorSpace: baseSpace, colorComponents: colorsArray.rgbNormalized.componentsJoined,
|
||||
locations: locations, count: colorsArray.count) else { return }
|
||||
|
||||
gradientCache = cachedGradient
|
||||
gradient = cachedGradient
|
||||
gradientCache = newGradient
|
||||
gradient = newGradient
|
||||
}
|
||||
|
||||
let halfX = bounds.size.width / 2.0
|
||||
let floatPi = CGFloat.pi
|
||||
let rotateSpeed = clockwise == true ? gradientRotateSpeed : gradientRotateSpeed * -1
|
||||
let angleInRadians = Conversion.degreesToRadians(value: rotateSpeed * CGFloat(angle) - 90)
|
||||
let rotateSpeed = clockwise == true ? gradientRotateSpeed : gradientRotateSpeed * -1.0
|
||||
let angleInRadians = (rotateSpeed * CGFloat(angle) - 90.0).radians
|
||||
let oppositeAngle = angleInRadians > floatPi ? angleInRadians - floatPi : angleInRadians + floatPi
|
||||
|
||||
let startPoint = CGPoint(x: (cos(angleInRadians) * halfX) + halfX, y: (sin(angleInRadians) * halfX) + halfX)
|
||||
@@ -540,18 +463,16 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
|
||||
private func gradientLocationsFor(colorCount: Int, gradientWidth: CGFloat) -> [CGFloat] {
|
||||
if colorCount == 0 || gradientWidth == 0 {
|
||||
return []
|
||||
} else {
|
||||
let progressLineWidth = radius * progressThickness
|
||||
let firstPoint = gradientWidth/2 - (radius - progressLineWidth/2)
|
||||
let increment = (gradientWidth - (2*firstPoint))/CGFloat(colorCount - 1)
|
||||
|
||||
let locationsArray = (0..<colorCount).map { firstPoint + (CGFloat($0) * increment) }
|
||||
let result = locationsArray.map { $0 / gradientWidth }
|
||||
locationsCache = result
|
||||
return result
|
||||
}
|
||||
guard colorCount > 0, gradientWidth > 0 else { return [] }
|
||||
|
||||
let progressLineWidth = radius * progressThickness
|
||||
let firstPoint = gradientWidth / 2.0 - (radius - progressLineWidth / 2.0)
|
||||
let increment = (gradientWidth - (2.0 * firstPoint)) / CGFloat(colorCount - 1)
|
||||
|
||||
let locationsArray = (0..<colorCount).map { firstPoint + (CGFloat($0) * increment) }
|
||||
let result = locationsArray.map { $0 / gradientWidth }
|
||||
locationsCache = result
|
||||
return result
|
||||
}
|
||||
|
||||
private func invalidateGradientCache() {
|
||||
@@ -560,3 +481,76 @@ public class KDCircularProgress: UIView, CAAnimationDelegate {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Some helper extensions below
|
||||
|
||||
private extension Array where Element == UIColor {
|
||||
// Make sure every color in colors array is in RGB color space
|
||||
var rgbNormalized: [UIColor] {
|
||||
return map { color in
|
||||
guard color.cgColor.numberOfComponents == 2 else {
|
||||
return color
|
||||
}
|
||||
|
||||
let white: CGFloat = color.cgColor.components![0]
|
||||
return UIColor(red: white, green: white, blue: white, alpha: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
var componentsJoined: [CGFloat] {
|
||||
return flatMap { $0.cgColor.components ?? [] }
|
||||
}
|
||||
}
|
||||
|
||||
private extension Comparable {
|
||||
func clamp(lowerBound: Self, upperBound: Self) -> Self {
|
||||
return min(max(self, lowerBound), upperBound)
|
||||
}
|
||||
}
|
||||
|
||||
private extension FloatingPoint {
|
||||
var radians: Self {
|
||||
return self * .pi / Self(180)
|
||||
}
|
||||
|
||||
func mod(between left: Self, and right: Self, byIncrementing interval: Self) -> Self {
|
||||
assert(interval > 0)
|
||||
assert(interval <= right - left)
|
||||
assert(right > left)
|
||||
|
||||
if self >= left, self <= right {
|
||||
return self
|
||||
} else if self < left {
|
||||
return (self + interval).mod(between: left, and: right, byIncrementing: interval)
|
||||
} else {
|
||||
return (self - interval).mod(between: left, and: right, byIncrementing: interval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension BinaryFloatingPoint {
|
||||
func inverseLerp(min: Self, max: Self) -> Self {
|
||||
return (self - min) / (max - min)
|
||||
}
|
||||
|
||||
func lerp(min: Self, max: Self) -> Self {
|
||||
return (max - min) * self + min
|
||||
}
|
||||
|
||||
func colorLerp(minColor: UIColor, maxColor: UIColor) -> UIColor {
|
||||
let clampedValue = CGFloat(self.clamp(lowerBound: 0.0, upperBound: 1.0))
|
||||
let zero = CGFloat(0.0)
|
||||
|
||||
|
||||
var (r0, g0, b0, a0) = (zero, zero, zero, zero)
|
||||
minColor.getRed(&r0, green: &g0, blue: &b0, alpha: &a0)
|
||||
|
||||
var (r1, g1, b1, a1) = (zero, zero, zero, zero)
|
||||
maxColor.getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
|
||||
|
||||
return UIColor(red: clampedValue.lerp(min: r0, max: r1),
|
||||
green: clampedValue.lerp(min: g0, max: g1),
|
||||
blue: clampedValue.lerp(min: b0, max: b1),
|
||||
alpha: clampedValue.lerp(min: a0, max: a1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// swift-tools-version:4.2
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "KDCircularProgress",
|
||||
products: [
|
||||
.library(name: "KDCircularProgress", targets: ["KDCircularProgress"])
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "KDCircularProgress",
|
||||
path: "KDCircularProgress"
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -4,10 +4,6 @@
|
||||
[](http://cocoapods.org/pods/KDCircularProgress)
|
||||
[](http://cocoapods.org/pods/KDCircularProgress)
|
||||
|
||||
>
|
||||
`KDCircularProgress` master branch is now compatible with Swift 3 (tag 1.5.2). Check Swift 2 (tag 1.4.1) & Swift 2.3 (tag 1.4.5) branches for older versions.
|
||||
|
||||
|
||||
`KDCircularProgress` is a circular progress view written in Swift. It makes it possible to have gradients in the progress view, along with glows and animations.
|
||||
|
||||
KDCircularProgress also has `IBInspectable` and `IBDesignable` support, so you can configure and preview inside the `Interface Builder`.
|
||||
|
||||
Reference in New Issue
Block a user