├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── GradientProgressViewExample.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── GradientProgressViewExample
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── icon_tag.imageset
│ │ ├── Contents.json
│ │ └── icon_tag@2x.png
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── SceneDelegate.swift
└── ViewController.swift
├── KFGradientProgressView.podspec
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── GradientProgressView.swift
└── example.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GradientProgressViewExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 17E0711F2494B2CD0074069F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E0711E2494B2CD0074069F /* AppDelegate.swift */; };
11 | 17E071212494B2CD0074069F /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E071202494B2CD0074069F /* SceneDelegate.swift */; };
12 | 17E071232494B2CD0074069F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E071222494B2CD0074069F /* ViewController.swift */; };
13 | 17E071262494B2CD0074069F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 17E071242494B2CD0074069F /* Main.storyboard */; };
14 | 17E071282494B2D10074069F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 17E071272494B2D10074069F /* Assets.xcassets */; };
15 | 17E0712B2494B2D10074069F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 17E071292494B2D10074069F /* LaunchScreen.storyboard */; };
16 | 17E071352494B3630074069F /* GradientProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E071342494B3630074069F /* GradientProgressView.swift */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | 17E0711B2494B2CD0074069F /* GradientProgressViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GradientProgressViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
21 | 17E0711E2494B2CD0074069F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
22 | 17E071202494B2CD0074069F /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
23 | 17E071222494B2CD0074069F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
24 | 17E071252494B2CD0074069F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
25 | 17E071272494B2D10074069F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
26 | 17E0712A2494B2D10074069F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
27 | 17E0712C2494B2D10074069F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
28 | 17E071342494B3630074069F /* GradientProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GradientProgressView.swift; path = Sources/GradientProgressView.swift; sourceTree = SOURCE_ROOT; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 17E071182494B2CD0074069F /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | 17E071122494B2CD0074069F = {
43 | isa = PBXGroup;
44 | children = (
45 | 17E0711D2494B2CD0074069F /* GradientProgressViewExample */,
46 | 17E0711C2494B2CD0074069F /* Products */,
47 | );
48 | sourceTree = "";
49 | };
50 | 17E0711C2494B2CD0074069F /* Products */ = {
51 | isa = PBXGroup;
52 | children = (
53 | 17E0711B2494B2CD0074069F /* GradientProgressViewExample.app */,
54 | );
55 | name = Products;
56 | sourceTree = "";
57 | };
58 | 17E0711D2494B2CD0074069F /* GradientProgressViewExample */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 17E071332494B33E0074069F /* Sources */,
62 | 17E0711E2494B2CD0074069F /* AppDelegate.swift */,
63 | 17E071202494B2CD0074069F /* SceneDelegate.swift */,
64 | 17E071222494B2CD0074069F /* ViewController.swift */,
65 | 17E071242494B2CD0074069F /* Main.storyboard */,
66 | 17E071272494B2D10074069F /* Assets.xcassets */,
67 | 17E071292494B2D10074069F /* LaunchScreen.storyboard */,
68 | 17E0712C2494B2D10074069F /* Info.plist */,
69 | );
70 | path = GradientProgressViewExample;
71 | sourceTree = "";
72 | };
73 | 17E071332494B33E0074069F /* Sources */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 17E071342494B3630074069F /* GradientProgressView.swift */,
77 | );
78 | name = Sources;
79 | sourceTree = "";
80 | };
81 | /* End PBXGroup section */
82 |
83 | /* Begin PBXNativeTarget section */
84 | 17E0711A2494B2CD0074069F /* GradientProgressViewExample */ = {
85 | isa = PBXNativeTarget;
86 | buildConfigurationList = 17E0712F2494B2D10074069F /* Build configuration list for PBXNativeTarget "GradientProgressViewExample" */;
87 | buildPhases = (
88 | 17E071172494B2CD0074069F /* Sources */,
89 | 17E071182494B2CD0074069F /* Frameworks */,
90 | 17E071192494B2CD0074069F /* Resources */,
91 | );
92 | buildRules = (
93 | );
94 | dependencies = (
95 | );
96 | name = GradientProgressViewExample;
97 | productName = GradientProgressViewExample;
98 | productReference = 17E0711B2494B2CD0074069F /* GradientProgressViewExample.app */;
99 | productType = "com.apple.product-type.application";
100 | };
101 | /* End PBXNativeTarget section */
102 |
103 | /* Begin PBXProject section */
104 | 17E071132494B2CD0074069F /* Project object */ = {
105 | isa = PBXProject;
106 | attributes = {
107 | LastSwiftUpdateCheck = 1150;
108 | LastUpgradeCheck = 1150;
109 | ORGANIZATIONNAME = carefree;
110 | TargetAttributes = {
111 | 17E0711A2494B2CD0074069F = {
112 | CreatedOnToolsVersion = 11.5;
113 | };
114 | };
115 | };
116 | buildConfigurationList = 17E071162494B2CD0074069F /* Build configuration list for PBXProject "GradientProgressViewExample" */;
117 | compatibilityVersion = "Xcode 9.3";
118 | developmentRegion = en;
119 | hasScannedForEncodings = 0;
120 | knownRegions = (
121 | en,
122 | Base,
123 | );
124 | mainGroup = 17E071122494B2CD0074069F;
125 | productRefGroup = 17E0711C2494B2CD0074069F /* Products */;
126 | projectDirPath = "";
127 | projectRoot = "";
128 | targets = (
129 | 17E0711A2494B2CD0074069F /* GradientProgressViewExample */,
130 | );
131 | };
132 | /* End PBXProject section */
133 |
134 | /* Begin PBXResourcesBuildPhase section */
135 | 17E071192494B2CD0074069F /* Resources */ = {
136 | isa = PBXResourcesBuildPhase;
137 | buildActionMask = 2147483647;
138 | files = (
139 | 17E0712B2494B2D10074069F /* LaunchScreen.storyboard in Resources */,
140 | 17E071282494B2D10074069F /* Assets.xcassets in Resources */,
141 | 17E071262494B2CD0074069F /* Main.storyboard in Resources */,
142 | );
143 | runOnlyForDeploymentPostprocessing = 0;
144 | };
145 | /* End PBXResourcesBuildPhase section */
146 |
147 | /* Begin PBXSourcesBuildPhase section */
148 | 17E071172494B2CD0074069F /* Sources */ = {
149 | isa = PBXSourcesBuildPhase;
150 | buildActionMask = 2147483647;
151 | files = (
152 | 17E071232494B2CD0074069F /* ViewController.swift in Sources */,
153 | 17E0711F2494B2CD0074069F /* AppDelegate.swift in Sources */,
154 | 17E071212494B2CD0074069F /* SceneDelegate.swift in Sources */,
155 | 17E071352494B3630074069F /* GradientProgressView.swift in Sources */,
156 | );
157 | runOnlyForDeploymentPostprocessing = 0;
158 | };
159 | /* End PBXSourcesBuildPhase section */
160 |
161 | /* Begin PBXVariantGroup section */
162 | 17E071242494B2CD0074069F /* Main.storyboard */ = {
163 | isa = PBXVariantGroup;
164 | children = (
165 | 17E071252494B2CD0074069F /* Base */,
166 | );
167 | name = Main.storyboard;
168 | sourceTree = "";
169 | };
170 | 17E071292494B2D10074069F /* LaunchScreen.storyboard */ = {
171 | isa = PBXVariantGroup;
172 | children = (
173 | 17E0712A2494B2D10074069F /* Base */,
174 | );
175 | name = LaunchScreen.storyboard;
176 | sourceTree = "";
177 | };
178 | /* End PBXVariantGroup section */
179 |
180 | /* Begin XCBuildConfiguration section */
181 | 17E0712D2494B2D10074069F /* Debug */ = {
182 | isa = XCBuildConfiguration;
183 | buildSettings = {
184 | ALWAYS_SEARCH_USER_PATHS = NO;
185 | CLANG_ANALYZER_NONNULL = YES;
186 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
187 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
188 | CLANG_CXX_LIBRARY = "libc++";
189 | CLANG_ENABLE_MODULES = YES;
190 | CLANG_ENABLE_OBJC_ARC = YES;
191 | CLANG_ENABLE_OBJC_WEAK = YES;
192 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
193 | CLANG_WARN_BOOL_CONVERSION = YES;
194 | CLANG_WARN_COMMA = YES;
195 | CLANG_WARN_CONSTANT_CONVERSION = YES;
196 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
197 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
198 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
199 | CLANG_WARN_EMPTY_BODY = YES;
200 | CLANG_WARN_ENUM_CONVERSION = YES;
201 | CLANG_WARN_INFINITE_RECURSION = YES;
202 | CLANG_WARN_INT_CONVERSION = YES;
203 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
204 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
205 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
206 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
207 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
208 | CLANG_WARN_STRICT_PROTOTYPES = YES;
209 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
210 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
211 | CLANG_WARN_UNREACHABLE_CODE = YES;
212 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
213 | COPY_PHASE_STRIP = NO;
214 | DEBUG_INFORMATION_FORMAT = dwarf;
215 | ENABLE_STRICT_OBJC_MSGSEND = YES;
216 | ENABLE_TESTABILITY = YES;
217 | GCC_C_LANGUAGE_STANDARD = gnu11;
218 | GCC_DYNAMIC_NO_PIC = NO;
219 | GCC_NO_COMMON_BLOCKS = YES;
220 | GCC_OPTIMIZATION_LEVEL = 0;
221 | GCC_PREPROCESSOR_DEFINITIONS = (
222 | "DEBUG=1",
223 | "$(inherited)",
224 | );
225 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
226 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
227 | GCC_WARN_UNDECLARED_SELECTOR = YES;
228 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
229 | GCC_WARN_UNUSED_FUNCTION = YES;
230 | GCC_WARN_UNUSED_VARIABLE = YES;
231 | IPHONEOS_DEPLOYMENT_TARGET = 13.5;
232 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
233 | MTL_FAST_MATH = YES;
234 | ONLY_ACTIVE_ARCH = YES;
235 | SDKROOT = iphoneos;
236 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
237 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
238 | };
239 | name = Debug;
240 | };
241 | 17E0712E2494B2D10074069F /* Release */ = {
242 | isa = XCBuildConfiguration;
243 | buildSettings = {
244 | ALWAYS_SEARCH_USER_PATHS = NO;
245 | CLANG_ANALYZER_NONNULL = YES;
246 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
247 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
248 | CLANG_CXX_LIBRARY = "libc++";
249 | CLANG_ENABLE_MODULES = YES;
250 | CLANG_ENABLE_OBJC_ARC = YES;
251 | CLANG_ENABLE_OBJC_WEAK = YES;
252 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
253 | CLANG_WARN_BOOL_CONVERSION = YES;
254 | CLANG_WARN_COMMA = YES;
255 | CLANG_WARN_CONSTANT_CONVERSION = YES;
256 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
257 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
258 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
259 | CLANG_WARN_EMPTY_BODY = YES;
260 | CLANG_WARN_ENUM_CONVERSION = YES;
261 | CLANG_WARN_INFINITE_RECURSION = YES;
262 | CLANG_WARN_INT_CONVERSION = YES;
263 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
264 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
265 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
266 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
267 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
268 | CLANG_WARN_STRICT_PROTOTYPES = YES;
269 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
270 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
271 | CLANG_WARN_UNREACHABLE_CODE = YES;
272 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
273 | COPY_PHASE_STRIP = NO;
274 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
275 | ENABLE_NS_ASSERTIONS = NO;
276 | ENABLE_STRICT_OBJC_MSGSEND = YES;
277 | GCC_C_LANGUAGE_STANDARD = gnu11;
278 | GCC_NO_COMMON_BLOCKS = YES;
279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
281 | GCC_WARN_UNDECLARED_SELECTOR = YES;
282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
283 | GCC_WARN_UNUSED_FUNCTION = YES;
284 | GCC_WARN_UNUSED_VARIABLE = YES;
285 | IPHONEOS_DEPLOYMENT_TARGET = 13.5;
286 | MTL_ENABLE_DEBUG_INFO = NO;
287 | MTL_FAST_MATH = YES;
288 | SDKROOT = iphoneos;
289 | SWIFT_COMPILATION_MODE = wholemodule;
290 | SWIFT_OPTIMIZATION_LEVEL = "-O";
291 | VALIDATE_PRODUCT = YES;
292 | };
293 | name = Release;
294 | };
295 | 17E071302494B2D10074069F /* Debug */ = {
296 | isa = XCBuildConfiguration;
297 | buildSettings = {
298 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
299 | CODE_SIGN_STYLE = Automatic;
300 | INFOPLIST_FILE = GradientProgressViewExample/Info.plist;
301 | IPHONEOS_DEPLOYMENT_TARGET = 13.5;
302 | LD_RUNPATH_SEARCH_PATHS = (
303 | "$(inherited)",
304 | "@executable_path/Frameworks",
305 | );
306 | PRODUCT_BUNDLE_IDENTIFIER = com.carefree.GradientProgressViewExample;
307 | PRODUCT_NAME = "$(TARGET_NAME)";
308 | SWIFT_VERSION = 5.0;
309 | TARGETED_DEVICE_FAMILY = "1,2";
310 | };
311 | name = Debug;
312 | };
313 | 17E071312494B2D10074069F /* Release */ = {
314 | isa = XCBuildConfiguration;
315 | buildSettings = {
316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
317 | CODE_SIGN_STYLE = Automatic;
318 | INFOPLIST_FILE = GradientProgressViewExample/Info.plist;
319 | IPHONEOS_DEPLOYMENT_TARGET = 13.5;
320 | LD_RUNPATH_SEARCH_PATHS = (
321 | "$(inherited)",
322 | "@executable_path/Frameworks",
323 | );
324 | PRODUCT_BUNDLE_IDENTIFIER = com.carefree.GradientProgressViewExample;
325 | PRODUCT_NAME = "$(TARGET_NAME)";
326 | SWIFT_VERSION = 5.0;
327 | TARGETED_DEVICE_FAMILY = "1,2";
328 | };
329 | name = Release;
330 | };
331 | /* End XCBuildConfiguration section */
332 |
333 | /* Begin XCConfigurationList section */
334 | 17E071162494B2CD0074069F /* Build configuration list for PBXProject "GradientProgressViewExample" */ = {
335 | isa = XCConfigurationList;
336 | buildConfigurations = (
337 | 17E0712D2494B2D10074069F /* Debug */,
338 | 17E0712E2494B2D10074069F /* Release */,
339 | );
340 | defaultConfigurationIsVisible = 0;
341 | defaultConfigurationName = Release;
342 | };
343 | 17E0712F2494B2D10074069F /* Build configuration list for PBXNativeTarget "GradientProgressViewExample" */ = {
344 | isa = XCConfigurationList;
345 | buildConfigurations = (
346 | 17E071302494B2D10074069F /* Debug */,
347 | 17E071312494B2D10074069F /* Release */,
348 | );
349 | defaultConfigurationIsVisible = 0;
350 | defaultConfigurationName = Release;
351 | };
352 | /* End XCConfigurationList section */
353 | };
354 | rootObject = 17E071132494B2CD0074069F /* Project object */;
355 | }
356 |
--------------------------------------------------------------------------------
/GradientProgressViewExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GradientProgressViewExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // GradientProgressViewExample
4 | //
5 | // Created by carefree on 2020/6/13.
6 | // Copyright © 2020 carefree. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/Assets.xcassets/icon_tag.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "icon_tag@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/Assets.xcassets/icon_tag.imageset/icon_tag@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moliya/GradientProgressView/751692d1c731618227a0017df98f1a3581ff8992/GradientProgressViewExample/Assets.xcassets/icon_tag.imageset/icon_tag@2x.png
--------------------------------------------------------------------------------
/GradientProgressViewExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
57 |
65 |
66 |
67 |
68 |
69 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UILaunchStoryboardName
43 | LaunchScreen
44 | UIMainStoryboardFile
45 | Main
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // GradientProgressViewExample
4 | //
5 | // Created by carefree on 2020/6/13.
6 | // Copyright © 2020 carefree. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
20 | guard let _ = (scene as? UIWindowScene) else { return }
21 | }
22 |
23 | func sceneDidDisconnect(_ scene: UIScene) {
24 | // Called as the scene is being released by the system.
25 | // This occurs shortly after the scene enters the background, or when its session is discarded.
26 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
28 | }
29 |
30 | func sceneDidBecomeActive(_ scene: UIScene) {
31 | // Called when the scene has moved from an inactive state to an active state.
32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
33 | }
34 |
35 | func sceneWillResignActive(_ scene: UIScene) {
36 | // Called when the scene will move from an active state to an inactive state.
37 | // This may occur due to temporary interruptions (ex. an incoming phone call).
38 | }
39 |
40 | func sceneWillEnterForeground(_ scene: UIScene) {
41 | // Called as the scene transitions from the background to the foreground.
42 | // Use this method to undo the changes made on entering the background.
43 | }
44 |
45 | func sceneDidEnterBackground(_ scene: UIScene) {
46 | // Called as the scene transitions from the foreground to the background.
47 | // Use this method to save data, release shared resources, and store enough scene-specific state information
48 | // to restore the scene back to its current state.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/GradientProgressViewExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // GradientProgressViewExample
4 | //
5 | // Created by carefree on 2020/6/13.
6 | // Copyright © 2020 carefree. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | @IBOutlet weak var progressView1: GradientProgressView!
14 | @IBOutlet weak var progressView2: GradientProgressView!
15 | @IBOutlet weak var progressView3: GradientProgressView!
16 | @IBOutlet weak var progressView4: GradientProgressView!
17 |
18 | @IBOutlet weak var tagView: UIImageView!
19 | @IBOutlet weak var progressLabel: UILabel!
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 |
24 | //设置圆角
25 | progressView1.layer.cornerRadius = 5
26 | progressView2.layer.cornerRadius = 0
27 | progressView3.layer.cornerRadius = 10
28 | progressView4.layer.cornerRadius = 4
29 |
30 | //设置进度条圆角
31 | progressView1.progressCornerRadius = 5
32 | progressView2.progressCornerRadius = 0
33 | progressView3.progressCornerRadius = 6
34 | progressView4.progressCornerRadius = 3
35 |
36 | //设置内间距
37 | progressView3.progressEdgeInsets = UIEdgeInsets(top: 4, left: 5, bottom: 4, right: 5)
38 | progressView4.progressEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4)
39 |
40 | //设置纯色和渐变色
41 | progressView1.progressColors = [.green]
42 | progressView2.progressColors = [#colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1), #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1), #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)]
43 | progressView3.progressColors = [#colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1), #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1), #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1), #colorLiteral(red: 0.5843137503, green: 0.8235294223, blue: 0.4196078479, alpha: 1)]
44 | progressView4.progressColors = [.red]
45 |
46 | //动画时间
47 | progressView1.animationDuration = 1
48 | progressView2.animationDuration = 0.2
49 | progressView3.animationDuration = 1.2
50 | progressView4.animationDuration = 1.8
51 |
52 | //动画函数
53 | progressView1.timingFunction = CAMediaTimingFunction(name: .default)
54 | progressView2.timingFunction = CAMediaTimingFunction(name: .linear)
55 | progressView3.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
56 | progressView4.timingFunction = CAMediaTimingFunction(name: .easeOut)
57 |
58 | //更新回调
59 | progressView4.progressUpdating = {[unowned self] progress, frame in
60 | //更新Label的百分比
61 | let text = String(format: "%.0f", progress * 100)
62 | self.progressLabel.text = "\(text)%"
63 |
64 | //计算出标签的移动位置
65 | let newFrame = self.progressView4.convert(frame, to: self.self.progressView4.superview)
66 | let size: CGFloat = 36
67 | let tagFrame = CGRect(x: (newFrame.origin.x + newFrame.size.width) - size / 2.3, y: newFrame.origin.y - size, width: size, height: size)
68 | self.tagView.frame = tagFrame
69 | self.progressLabel.sizeToFit()
70 | self.progressLabel.center = CGPoint(x: self.tagView.center.x, y: self.tagView.center.y - 7)
71 | }
72 |
73 | //设置标签的初始位置
74 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
75 | let frame = self.progressView4.frame
76 | let size: CGFloat = 36
77 | let tagFrame = CGRect(x: frame.origin.x - size / 2.3, y: frame.origin.y - size, width: size, height: size)
78 | self.tagView.frame = tagFrame
79 | self.progressLabel.sizeToFit()
80 | self.progressLabel.center = CGPoint(x: self.tagView.center.x, y: self.tagView.center.y - 7)
81 | self.progressLabel.text = "0%"
82 | }
83 | }
84 |
85 | @IBAction func resetAction(_ sender: Any) {
86 | progressView1.progress = 0
87 | progressView2.progress = 0
88 | progressView3.progress = 0
89 | progressView4.progress = 0
90 | }
91 |
92 | @IBAction func startAction(_ sender: Any) {
93 | progressView1.setProgress(0.2 + progressView1.progress, animated: true)
94 | progressView2.setProgress(0.25 + progressView2.progress, animated: true)
95 | progressView3.setProgress(0.3 + progressView3.progress, animated: true)
96 | progressView4.setProgress(0.25 + progressView4.progress, animated: true)
97 | }
98 |
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/KFGradientProgressView.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "KFGradientProgressView"
4 | s.version = "1.5.0"
5 | s.summary = "一个简单的进度条控件"
6 | s.homepage = "https://github.com/moliya/GradientProgressView"
7 | s.license = "MIT"
8 | s.author = {'Carefree' => '946715806@qq.com'}
9 | s.source = { :git => "https://github.com/moliya/GradientProgressView.git", :tag => s.version}
10 | s.source_files = "Sources/*"
11 | s.requires_arc = true
12 | s.platform = :ios, '8.0'
13 | s.swift_version = '5.0'
14 |
15 | end
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 moliya
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "GradientProgressView",
8 | platforms: [
9 | .iOS(.v8)
10 | ],
11 | products: [
12 | .library(name: "GradientProgressView", targets: ["GradientProgressView"])
13 | ],
14 | dependencies: [
15 | // Dependencies declare other packages that this package depends on.
16 | // .package(url: /* package url */, from: "1.0.0"),
17 | ],
18 | targets: [
19 | .target(name: "GradientProgressView", dependencies: [], path: "Sources")
20 | ],
21 | swiftLanguageVersions: [.v5]
22 | )
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GradientProgressView
2 |
3 |
4 |
5 | ## 一个简单的进度条控件
6 |
7 | #### 示例图
8 |
9 | 
10 |
11 | - 支持设置纯色进度条、渐变进度条
12 | - 支持设置进度条的圆角
13 | - 支持设置进度条的内间距
14 | - 支持自定义高度、背景颜色
15 | - 支持设置动画时长、动画时间函数
16 | - 支持监听进度的更新回调
17 |
18 | ### 要求
19 |
20 | - Swift 5.0
21 | - Xcode 11
22 | - iOS 8.0+
23 |
24 | ### 使用
25 |
26 | 设置圆角
27 |
28 | ```swift
29 | //设置进度条圆角
30 | progressView.progressCornerRadius = 5
31 | ```
32 |
33 | 设置内间距
34 |
35 | ```swift
36 | //设置内间距
37 | progressView.progressEdgeInsets = UIEdgeInsets(top: 4, left: 5, bottom: 4, right: 5)
38 | ```
39 |
40 | 设置纯色和渐变色
41 |
42 | ```swift
43 | //设置纯色和渐变色
44 | progressView1.progressColors = [.green]
45 | progressView2.progressColors = [.green, .red]
46 | ```
47 |
48 | 设置动画时间时长
49 |
50 | ```swift
51 | //动画时间
52 | progressView.animationDuration = 1
53 | ```
54 |
55 | 设置动画时间函数
56 |
57 | ```swift
58 | //动画时间函数
59 | progressView.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
60 | ```
61 |
62 | 设置动画更新回调
63 |
64 | ```swift
65 | //动画更新回调
66 | progressView.progressUpdating = {[unowned self] progress, frame in
67 | //在这里可以获得当前的进度百分比和进度条的frame
68 | print(progress)
69 | print(frame)
70 | }
71 | ```
72 |
73 | 设置进度
74 |
75 | ```swift
76 | //设置进度
77 | progressView.setProgress(0.8, animated: true)
78 | ```
79 |
80 | ### 集成
81 |
82 | ##### CocoaPods
83 |
84 | ```ruby
85 | pod 'KFGradientProgressView'
86 | ```
87 |
88 | ##### Swift Package Manager
89 |
90 | ```swift
91 | dependencies: [
92 | .package(url: "https://github.com/moliya/GradientProgressView", from: "1.4.0")
93 | ]
94 | ```
95 |
96 |
--------------------------------------------------------------------------------
/Sources/GradientProgressView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GradientProgressView.swift
3 | // GradientProgressViewExample
4 | //
5 | // Created by carefree on 2020/6/13.
6 | // Copyright © 2020 carefree. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc(KFGradientProgressView)
12 | open class GradientProgressView: UIView {
13 |
14 | //进度条完成部分的渐变颜色,设置单个为纯色,设置多个为渐变色
15 | @objc
16 | public var progressColors: [UIColor] = [.systemBlue] {
17 | didSet {
18 | if progressColors.count == 0 {
19 | gradientLayer.colors = nil
20 | } else if progressColors.count == 1 {
21 | let color = progressColors[0]
22 | gradientLayer.colors = [color, color].map { $0.cgColor }
23 | } else {
24 | gradientLayer.colors = progressColors.map { $0.cgColor }
25 | }
26 | }
27 | }
28 |
29 | //进度条完成部分的圆角半径
30 | @objc
31 | public var progressCornerRadius: CGFloat = 0 {
32 | didSet {
33 | maskLayer.cornerRadius = progressCornerRadius
34 | }
35 | }
36 |
37 | //进度完成部分的内间距
38 | @objc
39 | public var progressEdgeInsets: UIEdgeInsets = .zero {
40 | didSet {
41 | setNeedsLayout()
42 | }
43 | }
44 |
45 | //当前进度
46 | @objc
47 | public var progress: Float {
48 | get {
49 | return privateProgress
50 | }
51 | set {
52 | setProgress(newValue, animated: false)
53 | }
54 | }
55 |
56 | //渐变Layer
57 | public let gradientLayer: CAGradientLayer = {
58 | let layer = CAGradientLayer()
59 | layer.anchorPoint = .zero
60 | layer.startPoint = .zero
61 | layer.endPoint = CGPoint(x: 1.0, y: 0.0)
62 |
63 | return layer
64 | }()
65 |
66 | //动画持续时间
67 | @objc
68 | public var animationDuration: TimeInterval = 0.3
69 |
70 | //动画时间函数
71 | @objc
72 | public var timingFunction: CAMediaTimingFunction = CAMediaTimingFunction(name: .default)
73 |
74 | //进度更新动画过程中的回调,在这里可以拿到当前进度及进度条的frame
75 | @objc
76 | public var progressUpdating: ((Float, CGRect) -> ())?
77 |
78 |
79 | private var privateProgress: Float = 0
80 | private let maskLayer: CALayer = {
81 | let layer = CALayer()
82 | layer.backgroundColor = UIColor.white.cgColor
83 |
84 | return layer
85 | }()
86 |
87 | // MARK: - Lifecycle
88 | required public init?(coder: NSCoder) {
89 | super.init(coder: coder)
90 |
91 | commonInit()
92 | }
93 |
94 | override public init(frame: CGRect) {
95 | super.init(frame: frame)
96 |
97 | commonInit()
98 | }
99 |
100 | open override func layoutSubviews() {
101 | super.layoutSubviews()
102 |
103 | gradientLayer.frame = bounds.inset(by: progressEdgeInsets)
104 | var bounds = gradientLayer.bounds
105 | bounds.size.width *= CGFloat(progress)
106 | maskLayer.frame = bounds
107 | }
108 |
109 | // MARK: - Private
110 | private func commonInit() {
111 | let color = progressColors[0]
112 | gradientLayer.colors = [color, color].map { $0.cgColor }
113 | gradientLayer.mask = maskLayer
114 | layer.insertSublayer(gradientLayer, at: 0)
115 | }
116 |
117 | @objc private func displayLinkAction() {
118 | guard let frame = maskLayer.presentation()?.frame else { return }
119 | let progress = frame.size.width / gradientLayer.frame.size.width
120 | progressUpdating?(Float(progress), frame)
121 | }
122 |
123 | // MARK: - Public
124 | @objc(setProgress:animated:)
125 | public func setProgress(_ progress: Float, animated: Bool) {
126 | let validProgress = min(1.0, max(0.0, progress))
127 | if privateProgress == validProgress {
128 | return
129 | }
130 | privateProgress = validProgress
131 |
132 | //动画时长
133 | var duration = animated ? animationDuration : 0
134 | if duration < 0 {
135 | duration = 0
136 | }
137 |
138 | var displayLink: CADisplayLink?
139 | if duration > 0 {
140 | //开启CADisplayLink
141 | displayLink = CADisplayLink(target: self, selector: #selector(displayLinkAction))
142 | //使用common模式,使其在UIScrollView滑动时依然能得到回调
143 | displayLink?.add(to: .main, forMode: .common)
144 | }
145 |
146 | CATransaction.begin()
147 | CATransaction.setAnimationDuration(duration)
148 | CATransaction.setAnimationTimingFunction(timingFunction)
149 | CATransaction.setCompletionBlock {
150 | //停止CADisplayLink
151 | displayLink?.invalidate()
152 | if duration == 0 {
153 | //更新回调
154 | self.progressUpdating?(validProgress, self.maskLayer.frame)
155 | } else {
156 | if let _ = self.maskLayer.presentation() {
157 | self.displayLinkAction()
158 | } else {
159 | self.progressUpdating?(validProgress, self.maskLayer.frame)
160 | }
161 | }
162 | }
163 |
164 | //更新maskLayer的frame
165 | var bounds = self.gradientLayer.bounds
166 | bounds.size.width *= CGFloat(validProgress)
167 | self.maskLayer.frame = bounds
168 |
169 | CATransaction.commit()
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/moliya/GradientProgressView/751692d1c731618227a0017df98f1a3581ff8992/example.gif
--------------------------------------------------------------------------------