├── Art └── Design.sketch ├── DVSRunProgressView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── devinshine.xcuserdatad │ └── xcschemes │ ├── DVSRunProgressView.xcscheme │ └── xcschememanagement.plist ├── DVSRunProgressView ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-60.png │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Icon-Spotlight-40.png │ │ ├── Icon-Spotlight-40@2x.png │ │ └── Icon-Spotlight-40@3x.png │ ├── Contents.json │ ├── first.imageset │ │ ├── Contents.json │ │ └── first.pdf │ ├── pic_header.imageset │ │ ├── Contents.json │ │ ├── pic_header.png │ │ ├── pic_header@2x.png │ │ └── pic_header@3x.png │ ├── pic_run_button.imageset │ │ ├── Contents.json │ │ ├── pic_run_button.png │ │ ├── pic_run_button@2x.png │ │ └── pic_run_button@3x.png │ └── second.imageset │ │ ├── Contents.json │ │ └── second.pdf ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Class │ ├── DVSRunProgressView.h │ └── DVSRunProgressView.m ├── Demo │ ├── CircleExampleController.h │ ├── CircleExampleController.m │ ├── CircleExampleController.xib │ ├── ExampleViewController.h │ ├── ExampleViewController.m │ ├── MarkExampleController.h │ ├── MarkExampleController.m │ ├── MarkExampleController.xib │ ├── RunAppViewController.h │ ├── RunAppViewController.m │ ├── RunProgressExampleController.h │ └── RunProgressExampleController.m ├── Info.plist ├── Vendor │ ├── UILabel+FlickerNumber.h │ └── UILabel+FlickerNumber.m └── main.m ├── LICENSE └── README.md /Art/Design.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/Art/Design.sketch -------------------------------------------------------------------------------- /DVSRunProgressView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2B024B7C1E20B7500091497D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024B7B1E20B7500091497D /* main.m */; }; 11 | 2B024B7F1E20B7500091497D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024B7E1E20B7500091497D /* AppDelegate.m */; }; 12 | 2B024B881E20B7500091497D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2B024B861E20B7500091497D /* Main.storyboard */; }; 13 | 2B024B8A1E20B7500091497D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2B024B891E20B7500091497D /* Assets.xcassets */; }; 14 | 2B024B8D1E20B7500091497D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2B024B8B1E20B7500091497D /* LaunchScreen.storyboard */; }; 15 | 2B024B991E20B79E0091497D /* DVSRunProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024B981E20B79E0091497D /* DVSRunProgressView.m */; }; 16 | 2B024B9C1E20BB9B0091497D /* RunAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024B9B1E20BB9B0091497D /* RunAppViewController.m */; }; 17 | 2B024B9F1E20BE210091497D /* UILabel+FlickerNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024B9E1E20BE210091497D /* UILabel+FlickerNumber.m */; }; 18 | 2B024BA21E20C0440091497D /* ExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024BA11E20C0440091497D /* ExampleViewController.m */; }; 19 | 2B024BA61E20C1080091497D /* CircleExampleController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024BA41E20C1080091497D /* CircleExampleController.m */; }; 20 | 2B024BA71E20C1080091497D /* CircleExampleController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2B024BA51E20C1080091497D /* CircleExampleController.xib */; }; 21 | 2B024BAB1E20C31B0091497D /* MarkExampleController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024BA91E20C31B0091497D /* MarkExampleController.m */; }; 22 | 2B024BAC1E20C31B0091497D /* MarkExampleController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2B024BAA1E20C31B0091497D /* MarkExampleController.xib */; }; 23 | 2B024BAF1E20CBFE0091497D /* RunProgressExampleController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B024BAE1E20CBFE0091497D /* RunProgressExampleController.m */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 2B024B771E20B7500091497D /* DVSRunProgressView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DVSRunProgressView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 2B024B7B1E20B7500091497D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 29 | 2B024B7D1E20B7500091497D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 30 | 2B024B7E1E20B7500091497D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 31 | 2B024B871E20B7500091497D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 32 | 2B024B891E20B7500091497D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 33 | 2B024B8C1E20B7500091497D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 34 | 2B024B8E1E20B7500091497D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | 2B024B971E20B79E0091497D /* DVSRunProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVSRunProgressView.h; sourceTree = ""; }; 36 | 2B024B981E20B79E0091497D /* DVSRunProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DVSRunProgressView.m; sourceTree = ""; }; 37 | 2B024B9A1E20BB9B0091497D /* RunAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RunAppViewController.h; sourceTree = ""; }; 38 | 2B024B9B1E20BB9B0091497D /* RunAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RunAppViewController.m; sourceTree = ""; }; 39 | 2B024B9D1E20BE210091497D /* UILabel+FlickerNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UILabel+FlickerNumber.h"; sourceTree = ""; }; 40 | 2B024B9E1E20BE210091497D /* UILabel+FlickerNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UILabel+FlickerNumber.m"; sourceTree = ""; }; 41 | 2B024BA01E20C0440091497D /* ExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleViewController.h; sourceTree = ""; }; 42 | 2B024BA11E20C0440091497D /* ExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleViewController.m; sourceTree = ""; }; 43 | 2B024BA31E20C1080091497D /* CircleExampleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleExampleController.h; sourceTree = ""; }; 44 | 2B024BA41E20C1080091497D /* CircleExampleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleExampleController.m; sourceTree = ""; }; 45 | 2B024BA51E20C1080091497D /* CircleExampleController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CircleExampleController.xib; sourceTree = ""; }; 46 | 2B024BA81E20C31B0091497D /* MarkExampleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkExampleController.h; sourceTree = ""; }; 47 | 2B024BA91E20C31B0091497D /* MarkExampleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MarkExampleController.m; sourceTree = ""; }; 48 | 2B024BAA1E20C31B0091497D /* MarkExampleController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MarkExampleController.xib; sourceTree = ""; }; 49 | 2B024BAD1E20CBFE0091497D /* RunProgressExampleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RunProgressExampleController.h; sourceTree = ""; }; 50 | 2B024BAE1E20CBFE0091497D /* RunProgressExampleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RunProgressExampleController.m; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | 2B024B741E20B7500091497D /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 2B024B6E1E20B7500091497D = { 65 | isa = PBXGroup; 66 | children = ( 67 | 2B024B791E20B7500091497D /* DVSRunProgressView */, 68 | 2B024B781E20B7500091497D /* Products */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | 2B024B781E20B7500091497D /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 2B024B771E20B7500091497D /* DVSRunProgressView.app */, 76 | ); 77 | name = Products; 78 | sourceTree = ""; 79 | }; 80 | 2B024B791E20B7500091497D /* DVSRunProgressView */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 2B024B941E20B7860091497D /* Class */, 84 | 2B024B951E20B7860091497D /* Demo */, 85 | 2B024B961E20B7860091497D /* Vendor */, 86 | 2B024B7A1E20B7500091497D /* Supporting Files */, 87 | ); 88 | path = DVSRunProgressView; 89 | sourceTree = ""; 90 | }; 91 | 2B024B7A1E20B7500091497D /* Supporting Files */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 2B024B7D1E20B7500091497D /* AppDelegate.h */, 95 | 2B024B7E1E20B7500091497D /* AppDelegate.m */, 96 | 2B024B861E20B7500091497D /* Main.storyboard */, 97 | 2B024B891E20B7500091497D /* Assets.xcassets */, 98 | 2B024B8B1E20B7500091497D /* LaunchScreen.storyboard */, 99 | 2B024B8E1E20B7500091497D /* Info.plist */, 100 | 2B024B7B1E20B7500091497D /* main.m */, 101 | ); 102 | name = "Supporting Files"; 103 | sourceTree = ""; 104 | }; 105 | 2B024B941E20B7860091497D /* Class */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 2B024B971E20B79E0091497D /* DVSRunProgressView.h */, 109 | 2B024B981E20B79E0091497D /* DVSRunProgressView.m */, 110 | ); 111 | path = Class; 112 | sourceTree = ""; 113 | }; 114 | 2B024B951E20B7860091497D /* Demo */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 2B024B9A1E20BB9B0091497D /* RunAppViewController.h */, 118 | 2B024B9B1E20BB9B0091497D /* RunAppViewController.m */, 119 | 2B024BA01E20C0440091497D /* ExampleViewController.h */, 120 | 2B024BA11E20C0440091497D /* ExampleViewController.m */, 121 | 2B024BA31E20C1080091497D /* CircleExampleController.h */, 122 | 2B024BA41E20C1080091497D /* CircleExampleController.m */, 123 | 2B024BA51E20C1080091497D /* CircleExampleController.xib */, 124 | 2B024BA81E20C31B0091497D /* MarkExampleController.h */, 125 | 2B024BA91E20C31B0091497D /* MarkExampleController.m */, 126 | 2B024BAA1E20C31B0091497D /* MarkExampleController.xib */, 127 | 2B024BAD1E20CBFE0091497D /* RunProgressExampleController.h */, 128 | 2B024BAE1E20CBFE0091497D /* RunProgressExampleController.m */, 129 | ); 130 | path = Demo; 131 | sourceTree = ""; 132 | }; 133 | 2B024B961E20B7860091497D /* Vendor */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 2B024B9D1E20BE210091497D /* UILabel+FlickerNumber.h */, 137 | 2B024B9E1E20BE210091497D /* UILabel+FlickerNumber.m */, 138 | ); 139 | path = Vendor; 140 | sourceTree = ""; 141 | }; 142 | /* End PBXGroup section */ 143 | 144 | /* Begin PBXNativeTarget section */ 145 | 2B024B761E20B7500091497D /* DVSRunProgressView */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = 2B024B911E20B7500091497D /* Build configuration list for PBXNativeTarget "DVSRunProgressView" */; 148 | buildPhases = ( 149 | 2B024B731E20B7500091497D /* Sources */, 150 | 2B024B741E20B7500091497D /* Frameworks */, 151 | 2B024B751E20B7500091497D /* Resources */, 152 | ); 153 | buildRules = ( 154 | ); 155 | dependencies = ( 156 | ); 157 | name = DVSRunProgressView; 158 | productName = DVSRunProgressView; 159 | productReference = 2B024B771E20B7500091497D /* DVSRunProgressView.app */; 160 | productType = "com.apple.product-type.application"; 161 | }; 162 | /* End PBXNativeTarget section */ 163 | 164 | /* Begin PBXProject section */ 165 | 2B024B6F1E20B7500091497D /* Project object */ = { 166 | isa = PBXProject; 167 | attributes = { 168 | LastUpgradeCheck = 0810; 169 | ORGANIZATIONNAME = DevinShine; 170 | TargetAttributes = { 171 | 2B024B761E20B7500091497D = { 172 | CreatedOnToolsVersion = 8.1; 173 | DevelopmentTeam = DQYAM3GKBQ; 174 | ProvisioningStyle = Automatic; 175 | }; 176 | }; 177 | }; 178 | buildConfigurationList = 2B024B721E20B7500091497D /* Build configuration list for PBXProject "DVSRunProgressView" */; 179 | compatibilityVersion = "Xcode 3.2"; 180 | developmentRegion = English; 181 | hasScannedForEncodings = 0; 182 | knownRegions = ( 183 | en, 184 | Base, 185 | ); 186 | mainGroup = 2B024B6E1E20B7500091497D; 187 | productRefGroup = 2B024B781E20B7500091497D /* Products */; 188 | projectDirPath = ""; 189 | projectRoot = ""; 190 | targets = ( 191 | 2B024B761E20B7500091497D /* DVSRunProgressView */, 192 | ); 193 | }; 194 | /* End PBXProject section */ 195 | 196 | /* Begin PBXResourcesBuildPhase section */ 197 | 2B024B751E20B7500091497D /* Resources */ = { 198 | isa = PBXResourcesBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | 2B024B8D1E20B7500091497D /* LaunchScreen.storyboard in Resources */, 202 | 2B024B8A1E20B7500091497D /* Assets.xcassets in Resources */, 203 | 2B024BAC1E20C31B0091497D /* MarkExampleController.xib in Resources */, 204 | 2B024BA71E20C1080091497D /* CircleExampleController.xib in Resources */, 205 | 2B024B881E20B7500091497D /* Main.storyboard in Resources */, 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | }; 209 | /* End PBXResourcesBuildPhase section */ 210 | 211 | /* Begin PBXSourcesBuildPhase section */ 212 | 2B024B731E20B7500091497D /* Sources */ = { 213 | isa = PBXSourcesBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | 2B024BAF1E20CBFE0091497D /* RunProgressExampleController.m in Sources */, 217 | 2B024B7F1E20B7500091497D /* AppDelegate.m in Sources */, 218 | 2B024B9C1E20BB9B0091497D /* RunAppViewController.m in Sources */, 219 | 2B024B991E20B79E0091497D /* DVSRunProgressView.m in Sources */, 220 | 2B024BA21E20C0440091497D /* ExampleViewController.m in Sources */, 221 | 2B024BA61E20C1080091497D /* CircleExampleController.m in Sources */, 222 | 2B024BAB1E20C31B0091497D /* MarkExampleController.m in Sources */, 223 | 2B024B9F1E20BE210091497D /* UILabel+FlickerNumber.m in Sources */, 224 | 2B024B7C1E20B7500091497D /* main.m in Sources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXSourcesBuildPhase section */ 229 | 230 | /* Begin PBXVariantGroup section */ 231 | 2B024B861E20B7500091497D /* Main.storyboard */ = { 232 | isa = PBXVariantGroup; 233 | children = ( 234 | 2B024B871E20B7500091497D /* Base */, 235 | ); 236 | name = Main.storyboard; 237 | sourceTree = ""; 238 | }; 239 | 2B024B8B1E20B7500091497D /* LaunchScreen.storyboard */ = { 240 | isa = PBXVariantGroup; 241 | children = ( 242 | 2B024B8C1E20B7500091497D /* Base */, 243 | ); 244 | name = LaunchScreen.storyboard; 245 | sourceTree = ""; 246 | }; 247 | /* End PBXVariantGroup section */ 248 | 249 | /* Begin XCBuildConfiguration section */ 250 | 2B024B8F1E20B7500091497D /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ALWAYS_SEARCH_USER_PATHS = NO; 254 | CLANG_ANALYZER_NONNULL = YES; 255 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 256 | CLANG_CXX_LIBRARY = "libc++"; 257 | CLANG_ENABLE_MODULES = YES; 258 | CLANG_ENABLE_OBJC_ARC = YES; 259 | CLANG_WARN_BOOL_CONVERSION = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 263 | CLANG_WARN_EMPTY_BODY = YES; 264 | CLANG_WARN_ENUM_CONVERSION = YES; 265 | CLANG_WARN_INFINITE_RECURSION = YES; 266 | CLANG_WARN_INT_CONVERSION = YES; 267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 268 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 269 | CLANG_WARN_UNREACHABLE_CODE = YES; 270 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 271 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 272 | COPY_PHASE_STRIP = NO; 273 | DEBUG_INFORMATION_FORMAT = dwarf; 274 | ENABLE_STRICT_OBJC_MSGSEND = YES; 275 | ENABLE_TESTABILITY = YES; 276 | GCC_C_LANGUAGE_STANDARD = gnu99; 277 | GCC_DYNAMIC_NO_PIC = NO; 278 | GCC_NO_COMMON_BLOCKS = YES; 279 | GCC_OPTIMIZATION_LEVEL = 0; 280 | GCC_PREPROCESSOR_DEFINITIONS = ( 281 | "DEBUG=1", 282 | "$(inherited)", 283 | ); 284 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 285 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 286 | GCC_WARN_UNDECLARED_SELECTOR = YES; 287 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 288 | GCC_WARN_UNUSED_FUNCTION = YES; 289 | GCC_WARN_UNUSED_VARIABLE = YES; 290 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 291 | MTL_ENABLE_DEBUG_INFO = YES; 292 | ONLY_ACTIVE_ARCH = YES; 293 | SDKROOT = iphoneos; 294 | }; 295 | name = Debug; 296 | }; 297 | 2B024B901E20B7500091497D /* Release */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ALWAYS_SEARCH_USER_PATHS = NO; 301 | CLANG_ANALYZER_NONNULL = YES; 302 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 303 | CLANG_CXX_LIBRARY = "libc++"; 304 | CLANG_ENABLE_MODULES = YES; 305 | CLANG_ENABLE_OBJC_ARC = YES; 306 | CLANG_WARN_BOOL_CONVERSION = YES; 307 | CLANG_WARN_CONSTANT_CONVERSION = YES; 308 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 309 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 310 | CLANG_WARN_EMPTY_BODY = YES; 311 | CLANG_WARN_ENUM_CONVERSION = YES; 312 | CLANG_WARN_INFINITE_RECURSION = YES; 313 | CLANG_WARN_INT_CONVERSION = YES; 314 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 315 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 316 | CLANG_WARN_UNREACHABLE_CODE = YES; 317 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 318 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 319 | COPY_PHASE_STRIP = NO; 320 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 321 | ENABLE_NS_ASSERTIONS = NO; 322 | ENABLE_STRICT_OBJC_MSGSEND = YES; 323 | GCC_C_LANGUAGE_STANDARD = gnu99; 324 | GCC_NO_COMMON_BLOCKS = YES; 325 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 326 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 327 | GCC_WARN_UNDECLARED_SELECTOR = YES; 328 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 329 | GCC_WARN_UNUSED_FUNCTION = YES; 330 | GCC_WARN_UNUSED_VARIABLE = YES; 331 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 332 | MTL_ENABLE_DEBUG_INFO = NO; 333 | SDKROOT = iphoneos; 334 | VALIDATE_PRODUCT = YES; 335 | }; 336 | name = Release; 337 | }; 338 | 2B024B921E20B7500091497D /* Debug */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 342 | DEVELOPMENT_TEAM = DQYAM3GKBQ; 343 | INFOPLIST_FILE = DVSRunProgressView/Info.plist; 344 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 345 | PRODUCT_BUNDLE_IDENTIFIER = com.shadev.DVSRunProgressView; 346 | PRODUCT_NAME = "$(TARGET_NAME)"; 347 | }; 348 | name = Debug; 349 | }; 350 | 2B024B931E20B7500091497D /* Release */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 354 | DEVELOPMENT_TEAM = DQYAM3GKBQ; 355 | INFOPLIST_FILE = DVSRunProgressView/Info.plist; 356 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 357 | PRODUCT_BUNDLE_IDENTIFIER = com.shadev.DVSRunProgressView; 358 | PRODUCT_NAME = "$(TARGET_NAME)"; 359 | }; 360 | name = Release; 361 | }; 362 | /* End XCBuildConfiguration section */ 363 | 364 | /* Begin XCConfigurationList section */ 365 | 2B024B721E20B7500091497D /* Build configuration list for PBXProject "DVSRunProgressView" */ = { 366 | isa = XCConfigurationList; 367 | buildConfigurations = ( 368 | 2B024B8F1E20B7500091497D /* Debug */, 369 | 2B024B901E20B7500091497D /* Release */, 370 | ); 371 | defaultConfigurationIsVisible = 0; 372 | defaultConfigurationName = Release; 373 | }; 374 | 2B024B911E20B7500091497D /* Build configuration list for PBXNativeTarget "DVSRunProgressView" */ = { 375 | isa = XCConfigurationList; 376 | buildConfigurations = ( 377 | 2B024B921E20B7500091497D /* Debug */, 378 | 2B024B931E20B7500091497D /* Release */, 379 | ); 380 | defaultConfigurationIsVisible = 0; 381 | }; 382 | /* End XCConfigurationList section */ 383 | }; 384 | rootObject = 2B024B6F1E20B7500091497D /* Project object */; 385 | } 386 | -------------------------------------------------------------------------------- /DVSRunProgressView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DVSRunProgressView.xcodeproj/xcuserdata/devinshine.xcuserdatad/xcschemes/DVSRunProgressView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /DVSRunProgressView.xcodeproj/xcuserdata/devinshine.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DVSRunProgressView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 2B024B761E20B7500091497D 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /DVSRunProgressView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /DVSRunProgressView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-Spotlight-40.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-60.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Small@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Small@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-Spotlight-40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-Spotlight-40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-60@3x.png", 49 | "scale" : "3x" 50 | } 51 | ], 52 | "info" : { 53 | "version" : 1, 54 | "author" : "xcode" 55 | } 56 | } -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-60.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/first.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "first.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/first.imageset/first.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/first.imageset/first.pdf -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/pic_header.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "pic_header.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "pic_header@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "pic_header@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/pic_header.imageset/pic_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/pic_header.imageset/pic_header.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/pic_header.imageset/pic_header@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/pic_header.imageset/pic_header@2x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/pic_header.imageset/pic_header@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/pic_header.imageset/pic_header@3x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/pic_run_button.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "pic_run_button.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "pic_run_button@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "pic_run_button@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/pic_run_button.imageset/pic_run_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/pic_run_button.imageset/pic_run_button.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/pic_run_button.imageset/pic_run_button@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/pic_run_button.imageset/pic_run_button@2x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/pic_run_button.imageset/pic_run_button@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/pic_run_button.imageset/pic_run_button@3x.png -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/second.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "second.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DVSRunProgressView/Assets.xcassets/second.imageset/second.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevinShine/DVSRunProgressView/da42808d4a0f9e66f2239308d1ccc2d67bfc867c/DVSRunProgressView/Assets.xcassets/second.imageset/second.pdf -------------------------------------------------------------------------------- /DVSRunProgressView/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 | 27 | 28 | -------------------------------------------------------------------------------- /DVSRunProgressView/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 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 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 | 127 | 133 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /DVSRunProgressView/Class/DVSRunProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DVSRunProgressView.h 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | /// Progress type 14 | typedef NS_OPTIONS(NSUInteger, DVSRunProgressViewType){ 15 | DVSRunProgressViewTypeNormal = 0, 16 | DVSRunProgressViewTypeGradient, 17 | }; 18 | 19 | /** The block invoked in animation completion */ 20 | typedef void(^DVSRunProgressViewCompletionBlock)(void); 21 | 22 | IB_DESIGNABLE 23 | 24 | @interface DVSRunProgressView : UIView 25 | 26 | /** The basic duration of the object. Defaults to 1. */ 27 | @property(nonatomic, assign) IBInspectable CFTimeInterval duration; 28 | 29 | /** The start angle. (e.g. 225) */ 30 | @property(nonatomic, assign) IBInspectable CGFloat startAngle; 31 | 32 | /** The end angle. (e.g. 45) */ 33 | @property(nonatomic, assign) IBInspectable CGFloat endAngle; 34 | 35 | /** The radius offset. */ 36 | @property(nonatomic, assign) IBInspectable CGFloat circleRadiusOffset; 37 | 38 | /** The maximum number of objects the mark should hold. */ 39 | @property(nonatomic, assign) IBInspectable NSUInteger markCount; 40 | 41 | /** The mark height */ 42 | @property(nonatomic, assign) IBInspectable CGFloat markHeight; 43 | 44 | /** The normal color */ 45 | @property(nonatomic, strong) IBInspectable UIColor *normalColor; 46 | 47 | /** The select color */ 48 | @property(nonatomic, strong) IBInspectable UIColor *selectColor; 49 | 50 | /** The progress type */ 51 | @property(nonatomic, assign) DVSRunProgressViewType type; 52 | 53 | /** The color array in gradient mode, which is equivalent to the colors of CAGradientLayer */ 54 | @property(nonatomic, nullable, copy) NSArray *gradientColors; 55 | 56 | /** The array of positions in the gradient mode, which is equivalent to the locations of the CAGradientLayer */ 57 | @property(nonatomic, nullable, copy) NSArray *gradientLocations; 58 | 59 | /** The startPoint in gradient mode, which is equivalent to the startPoint of CAGradientLayer */ 60 | @property(nonatomic, assign) IBInspectable CGPoint gradientStartPoint; 61 | 62 | /** The endPoint in gradient mode, which is equivalent to the endPoint of CAGradientLayer */ 63 | @property(nonatomic, assign) IBInspectable CGPoint gradientEndPoint; 64 | 65 | - (instancetype)init UNAVAILABLE_ATTRIBUTE; 66 | + (instancetype)new UNAVAILABLE_ATTRIBUTE; 67 | 68 | #pragma mark - Access Methods 69 | 70 | ///============================================================================= 71 | /// @name Access Methods 72 | ///============================================================================= 73 | 74 | /** 75 | Runs the animation based on a given percentage value 76 | @param percent The interval is [0,1]. 77 | */ 78 | - (void)runAnimationWithPercent:(CGFloat)percent; 79 | 80 | /** 81 | Runs the animation based on a given percentage value 82 | @param percent The interval is [0,1]. 83 | @param block A completion block when animation completion. 84 | */ 85 | - (void)runAnimationWithPercent:(CGFloat)percent 86 | completionBlock:(nullable DVSRunProgressViewCompletionBlock)block; 87 | 88 | /** 89 | Set the start color and end color, the type will be change Gradient. 90 | The locations will become [0,1]. The start and end points will become [0.5,0] and [0.5,1]. 91 | @param startColor The start color 92 | @param endColor The end color 93 | */ 94 | - (void)setEasyGradientColor:(UIColor *)startColor 95 | endColor:(UIColor *)endColor; 96 | @end 97 | 98 | NS_ASSUME_NONNULL_END 99 | -------------------------------------------------------------------------------- /DVSRunProgressView/Class/DVSRunProgressView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DVSRunProgressView.m 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import "DVSRunProgressView.h" 10 | 11 | #define kMarkCountDefault 100 12 | #define RGBA(c,a) [UIColor colorWithRed:((c>>16)&0xFF)/256.0 green:((c>>8)&0xFF)/256.0 blue:((c)&0xFF)/256.0 alpha:a] 13 | #define RGB(c) RGBA(c,1) 14 | 15 | static inline CGFloat angle2Radian(CGFloat angle) { 16 | return M_PI * angle / 180.0; 17 | } 18 | 19 | @interface DVSRunProgressView () 20 | @property(nonatomic, strong) CALayer *normalLayer; 21 | @property(nonatomic, strong) CALayer *selectLayer; 22 | @property(nonatomic, strong) CAShapeLayer *gradientMaskLayer; 23 | @property(nonatomic, strong) NSMutableArray *markPathArray; 24 | @property(nonatomic, assign) CGFloat currentPercent; 25 | @property(nullable, nonatomic, copy) DVSRunProgressViewCompletionBlock completionBlock; 26 | @end 27 | 28 | @implementation DVSRunProgressView 29 | #pragma mark - Init 30 | 31 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 32 | if (self = [super initWithCoder:aDecoder]) { 33 | [self initDefaultData]; 34 | [self configureUI]; 35 | } 36 | return self; 37 | } 38 | 39 | - (instancetype)initWithFrame:(CGRect)frame { 40 | if (self = [super initWithFrame:frame]) { 41 | [self initDefaultData]; 42 | [self configureUI]; 43 | } 44 | return self; 45 | } 46 | 47 | - (instancetype)init { 48 | @throw [NSException exceptionWithName:@"DVSCircleProgressView init error" reason:@"Use 'initWithFrame:' instead." userInfo:nil]; 49 | return [self initWithFrame:CGRectZero]; 50 | } 51 | 52 | #pragma mark - Setter 53 | 54 | - (void)setStartAngle:(CGFloat)startAngle { 55 | _startAngle = startAngle; 56 | [self reset]; 57 | [self configureUI]; 58 | } 59 | 60 | - (void)setEndAngle:(CGFloat)endAngle { 61 | _endAngle = endAngle; 62 | [self reset]; 63 | [self configureUI]; 64 | } 65 | 66 | - (void)setMarkCount:(NSUInteger)markCount { 67 | _markCount = markCount; 68 | [self reset]; 69 | [self configureUI]; 70 | } 71 | 72 | - (void)setNormalColor:(UIColor *)normalColor { 73 | _normalColor = normalColor; 74 | [self reset]; 75 | [self configureUI]; 76 | } 77 | 78 | - (void)setSelectColor:(UIColor *)selectColor { 79 | _selectColor = selectColor; 80 | [self reset]; 81 | [self configureUI]; 82 | } 83 | 84 | - (void)setMarkHeight:(CGFloat)markHeight { 85 | _markHeight = markHeight; 86 | [self reset]; 87 | [self configureUI]; 88 | } 89 | 90 | - (void)setCircleRadiusOffset:(CGFloat)circleRadiusOffset { 91 | _circleRadiusOffset = circleRadiusOffset; 92 | [self reset]; 93 | [self configureUI]; 94 | } 95 | 96 | - (void)setGradientColors:(NSArray *)gradientColors { 97 | _gradientColors = [gradientColors copy]; 98 | [self reset]; 99 | [self configureUI]; 100 | } 101 | 102 | - (void)setGradientLocations:(NSArray *)gradientLocations { 103 | _gradientLocations = gradientLocations; 104 | [self reset]; 105 | [self configureUI]; 106 | } 107 | 108 | - (void)setGradientStartPoint:(CGPoint)gradientStartPoint { 109 | _gradientStartPoint = gradientStartPoint; 110 | [self reset]; 111 | [self configureUI]; 112 | } 113 | 114 | - (void)setGradientEndPoint:(CGPoint)gradientEndPoint { 115 | _gradientEndPoint = gradientEndPoint; 116 | [self reset]; 117 | [self configureUI]; 118 | } 119 | 120 | - (void)setEasyGradientColor:(UIColor *)startColor 121 | endColor:(UIColor *)endColor { 122 | _gradientColors = @[(__bridge id)startColor.CGColor,(__bridge id)endColor.CGColor]; 123 | _gradientLocations = @[@0.0,@1.0]; 124 | _gradientStartPoint = CGPointMake(0.5, 0); 125 | _gradientEndPoint = CGPointMake(0.5, 1); 126 | _type = DVSRunProgressViewTypeGradient; 127 | [self reset]; 128 | [self configureUI]; 129 | } 130 | 131 | #pragma mark - Private 132 | 133 | - (void)initDefaultData { 134 | _currentPercent = 0.f; 135 | _duration = 1.f; 136 | _type = DVSRunProgressViewTypeNormal; 137 | _startAngle = -225.0; 138 | _endAngle = 45.0; 139 | _markCount = kMarkCountDefault; 140 | _normalColor = RGB(0xE0E2E4); 141 | _selectColor = RGB(0x7DCFA7); 142 | _markHeight = 20.f; 143 | _circleRadiusOffset = -20.f; 144 | 145 | _gradientColors = @[(__bridge id)RGB(0xFF9B55).CGColor,(__bridge id)RGB(0x08BB08).CGColor,(__bridge id)RGB(0xB92501).CGColor]; 146 | _gradientLocations = @[@0.0, @0.4, @1.0]; 147 | _gradientStartPoint = CGPointMake(0.5, 0); 148 | _gradientEndPoint = CGPointMake(0.5, 1); 149 | } 150 | 151 | - (void)configureUI{ 152 | CGFloat perRadian = fabs(angle2Radian(_startAngle - _endAngle)) / _markCount; 153 | 154 | CGFloat width = self.frame.size.width; 155 | CGPoint centers = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2); 156 | 157 | UIBezierPath *maskPath = [UIBezierPath bezierPath]; 158 | _markPathArray = @[].mutableCopy; 159 | for (int i = 0; i < _markCount; i++) { 160 | CGFloat start = (angle2Radian(_startAngle) + perRadian * i); 161 | // 除以2的话则是每个刻度之间相隔的刻度正好为一个刻度单位,如果除以 3 则相隔 2 个刻度单位,简单的说这个值越大,刻度的宽度越细 162 | CGFloat end = start + perRadian / 3; 163 | UIBezierPath *markPath = [UIBezierPath bezierPathWithArcCenter:centers radius:width/2 + _circleRadiusOffset startAngle:start endAngle:end clockwise:YES]; 164 | [maskPath appendPath:markPath]; 165 | // 将每个 path 添加到 array 当中,逐帧动画的时候使用,只有渐变动画才会需要用到逐帧动画这个方式 166 | [_markPathArray addObject:(__bridge id)((UIBezierPath *)[maskPath copy]).CGPath]; 167 | } 168 | 169 | _normalLayer = [CALayer layer]; 170 | _normalLayer.frame = self.bounds; 171 | _normalLayer.backgroundColor = _normalColor.CGColor; 172 | _normalLayer.mask = [self generateMaskLayerWithPath:maskPath]; 173 | 174 | if (_type == DVSRunProgressViewTypeNormal) { 175 | UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:centers radius:width/2 + _circleRadiusOffset startAngle:angle2Radian(_startAngle) endAngle:angle2Radian(_endAngle) clockwise:YES]; 176 | CAShapeLayer *selectLayer = [CAShapeLayer layer]; 177 | selectLayer.path = circlePath.CGPath; 178 | selectLayer.frame = self.bounds; 179 | selectLayer.fillColor = [UIColor clearColor].CGColor; 180 | selectLayer.lineWidth = _markHeight; 181 | selectLayer.strokeColor = _selectColor.CGColor; 182 | selectLayer.strokeEnd = 0.0; 183 | selectLayer.mask = [self generateMaskLayerWithPath:maskPath]; 184 | _selectLayer = selectLayer; 185 | }else if(_type == DVSRunProgressViewTypeGradient){ 186 | _gradientMaskLayer = [self generateMaskLayerWithPath:[UIBezierPath bezierPath]]; 187 | CAGradientLayer *gradientLayer = [CAGradientLayer layer]; 188 | gradientLayer.frame = self.bounds; 189 | gradientLayer.colors = _gradientColors; 190 | gradientLayer.locations = _gradientLocations; 191 | gradientLayer.startPoint = _gradientStartPoint; 192 | gradientLayer.endPoint = _gradientEndPoint; 193 | gradientLayer.mask = _gradientMaskLayer; 194 | _selectLayer = gradientLayer; 195 | }else { 196 | @throw [NSException exceptionWithName:@"_type error" reason:@"Use DVSRunProgressViewTypeGradient or DVSRunProgressViewTypeNormal instead." userInfo:nil]; 197 | } 198 | 199 | [self.layer addSublayer:_normalLayer]; 200 | [self.layer addSublayer:_selectLayer]; 201 | } 202 | 203 | - (CAShapeLayer *)generateMaskLayerWithPath:(UIBezierPath *)path { 204 | CAShapeLayer *maskLayer = [CAShapeLayer layer]; 205 | maskLayer.path = path.CGPath; 206 | maskLayer.strokeColor = [UIColor whiteColor].CGColor; 207 | maskLayer.lineWidth = _markHeight; 208 | return maskLayer; 209 | } 210 | 211 | - (NSArray *)generateMarkArrayToPercent:(CGFloat)percent { 212 | if (!_markPathArray || _markPathArray.count == 0) { 213 | return nil; 214 | } 215 | NSMutableArray *result = @[].mutableCopy; 216 | NSUInteger targetCount = _markPathArray.count * percent; 217 | for (int i = 0; i < targetCount; i++) { 218 | [result addObject:_markPathArray[i]]; 219 | } 220 | return result; 221 | } 222 | 223 | - (void)reset { 224 | if (_normalLayer) { 225 | [_normalLayer removeFromSuperlayer]; 226 | _normalLayer = nil; 227 | } 228 | 229 | if (_selectLayer) { 230 | [_selectLayer removeFromSuperlayer]; 231 | _selectLayer = nil; 232 | } 233 | 234 | if (_markPathArray) { 235 | _markPathArray = nil; 236 | } 237 | } 238 | 239 | #pragma mark - Public 240 | 241 | - (void)runAnimationWithPercent:(CGFloat)percent { 242 | [self runAnimationWithPercent:percent completionBlock:nil]; 243 | } 244 | 245 | - (void)runAnimationWithPercent:(CGFloat)percent 246 | completionBlock:(DVSRunProgressViewCompletionBlock)block { 247 | // Check Valid 248 | if (percent < 0) { 249 | percent = 0; 250 | }else if(percent > 1) { 251 | percent = 1; 252 | } 253 | 254 | if (_type == DVSRunProgressViewTypeNormal) { 255 | [CATransaction begin]; 256 | [CATransaction setCompletionBlock:block]; 257 | [CATransaction setAnimationDuration:_duration]; 258 | ((CAShapeLayer *)_selectLayer).strokeEnd = percent; 259 | [CATransaction commit]; 260 | 261 | _currentPercent = percent; 262 | }else if(_type == DVSRunProgressViewTypeGradient){ 263 | _completionBlock = block; 264 | 265 | CAKeyframeAnimation *anim = [CAKeyframeAnimation animation]; 266 | anim.delegate = self; 267 | anim.duration = _duration; 268 | anim.keyPath = @"path"; 269 | anim.values = [self generateMarkArrayToPercent:percent]; 270 | anim.removedOnCompletion = NO; 271 | anim.fillMode = kCAFillModeForwards; 272 | anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 273 | [_gradientMaskLayer addAnimation:anim forKey:nil]; 274 | 275 | _currentPercent = percent; 276 | } 277 | } 278 | 279 | #pragma mark - CAAnimationDelegate 280 | 281 | 282 | - (void)animationDidStart:(CAAnimation *)anim { 283 | 284 | } 285 | 286 | 287 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { 288 | if (_completionBlock) { 289 | _completionBlock(); 290 | } 291 | } 292 | 293 | @end 294 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/CircleExampleController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CircleExampleController.h 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CircleExampleController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/CircleExampleController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CircleExampleController.m 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import "CircleExampleController.h" 10 | #define RGBA(c,a) [UIColor colorWithRed:((c>>16)&0xFF)/256.0 green:((c>>8)&0xFF)/256.0 blue:((c)&0xFF)/256.0 alpha:a] 11 | #define RGB(c) RGBA(c,1) 12 | #define BackgroundColor RGB(0xD58989) 13 | 14 | @interface CircleExampleController () 15 | @property (weak, nonatomic) IBOutlet UIView *circleView; 16 | @property(nonatomic, strong) CAShapeLayer *maskLayer; 17 | @end 18 | 19 | @implementation CircleExampleController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | 24 | int width = self.circleView.bounds.size.width; 25 | int radius = width/2 - 20; 26 | CGPoint centers = CGPointMake(self.circleView.bounds.size.width / 2, self.circleView.bounds.size.height / 2); 27 | 28 | UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:centers radius:radius startAngle:-M_PI endAngle:M_PI clockwise:YES]; 29 | CAShapeLayer *maskLayer = [CAShapeLayer layer]; 30 | maskLayer.path = path.CGPath; 31 | maskLayer.strokeColor = [UIColor whiteColor].CGColor; 32 | maskLayer.fillColor = [UIColor clearColor].CGColor; 33 | maskLayer.lineCap = kCALineCapRound; 34 | maskLayer.lineWidth = 10; 35 | maskLayer.strokeEnd = 0.5; 36 | 37 | CAShapeLayer *colorLayer = [CAShapeLayer layer]; 38 | colorLayer.frame = self.circleView.bounds; 39 | colorLayer.backgroundColor = BackgroundColor.CGColor; 40 | 41 | 42 | colorLayer.mask = maskLayer; 43 | 44 | [self.circleView.layer addSublayer:colorLayer]; 45 | 46 | _maskLayer = maskLayer; 47 | } 48 | 49 | - (IBAction)increaseAction:(id)sender { 50 | [CATransaction begin]; 51 | [CATransaction setAnimationDuration:1.f]; 52 | _maskLayer.strokeEnd = 1.f; 53 | [CATransaction commit]; 54 | } 55 | 56 | - (IBAction)decreaseAction:(id)sender { 57 | [CATransaction begin]; 58 | [CATransaction setAnimationDuration:1.f]; 59 | _maskLayer.strokeEnd = 0.3f; 60 | [CATransaction commit]; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/CircleExampleController.xib: -------------------------------------------------------------------------------- 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 | 41 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/ExampleViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.h 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ExampleViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/ExampleViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.m 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import "ExampleViewController.h" 10 | 11 | @interface ExampleViewController () 12 | @property (nonatomic, strong) NSMutableArray *titles; 13 | @property (nonatomic, strong) NSMutableArray *classNames; 14 | 15 | @end 16 | 17 | @implementation ExampleViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | self.title = @"Practice"; 22 | 23 | self.titles = @[].mutableCopy; 24 | self.classNames = @[].mutableCopy; 25 | [self addCell:@"Circle Example" class:@"CircleExampleController"]; 26 | [self addCell:@"Mark Example" class:@"MarkExampleController"]; 27 | [self addCell:@"RunProgress Example" class:@"RunProgressExampleController"]; 28 | [self.tableView reloadData]; 29 | } 30 | 31 | - (void)addCell:(NSString *)title class:(NSString *)className { 32 | [self.titles addObject:title]; 33 | [self.classNames addObject:className]; 34 | } 35 | 36 | #pragma mark - Table view data source 37 | 38 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 39 | return _titles.count; 40 | } 41 | 42 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 43 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Animation"]; 44 | if (!cell) { 45 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Animation"]; 46 | } 47 | cell.textLabel.text = _titles[indexPath.row]; 48 | return cell; 49 | } 50 | 51 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 52 | NSString *className = self.classNames[indexPath.row]; 53 | Class class = NSClassFromString(className); 54 | if (class) { 55 | UIViewController *ctrl = class.new; 56 | ctrl.title = _titles[indexPath.row]; 57 | [self.navigationController pushViewController:ctrl animated:YES]; 58 | } 59 | [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/MarkExampleController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MarkExampleController.h 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MarkExampleController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/MarkExampleController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MarkExampleController.m 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import "MarkExampleController.h" 10 | #define RGBA(c,a) [UIColor colorWithRed:((c>>16)&0xFF)/256.0 green:((c>>8)&0xFF)/256.0 blue:((c)&0xFF)/256.0 alpha:a] 11 | #define RGB(c) RGBA(c,1) 12 | #define BackgroundColor RGB(0xD58989) 13 | 14 | @interface MarkExampleController () 15 | @property (weak, nonatomic) IBOutlet UIView *markView; 16 | @property (weak, nonatomic) IBOutlet UIView *markAnimationView; 17 | @property(nonatomic, strong) CALayer *normalLayer; 18 | 19 | @end 20 | 21 | @implementation MarkExampleController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | 26 | int width = self.markView.bounds.size.width; 27 | int radius = width/2 - 20; 28 | CGPoint centers = CGPointMake(self.markView.bounds.size.width / 2, self.markView.bounds.size.height / 2); 29 | 30 | // 1. 31 | CALayer *normalLayer = [CALayer layer]; 32 | normalLayer.frame = self.markView.bounds; 33 | normalLayer.backgroundColor = BackgroundColor.CGColor; 34 | 35 | // 2. 36 | UIBezierPath *maskPath = [UIBezierPath bezierPath]; 37 | int markCount = 90; 38 | CGFloat startRadian = - (225.0 / 180.0 * M_PI); 39 | CGFloat endRadian = 45.0 / 180.0 * M_PI; 40 | CGFloat perRadian = fabs(startRadian - endRadian) / markCount; 41 | for (int i = 0; i < markCount; i++) { 42 | CGFloat start = (startRadian + perRadian * i); 43 | CGFloat end = start + perRadian / 2; 44 | UIBezierPath *markPath = [UIBezierPath bezierPathWithArcCenter:centers radius:radius startAngle:start endAngle:end clockwise:YES]; 45 | [maskPath appendPath:markPath]; 46 | } 47 | 48 | CAShapeLayer *maskLayer = [CAShapeLayer layer]; 49 | maskLayer.path = maskPath.CGPath; 50 | maskLayer.strokeColor = [UIColor whiteColor].CGColor; 51 | maskLayer.lineWidth = 10.f; 52 | // 3. 53 | normalLayer.mask = maskLayer; 54 | 55 | [self.markView.layer addSublayer:normalLayer]; 56 | 57 | [self initAnimationView]; 58 | } 59 | 60 | - (void)initAnimationView { 61 | int width = self.markAnimationView.bounds.size.width; 62 | int radius = width/2 - 20; 63 | CGPoint centers = CGPointMake(self.markAnimationView.bounds.size.width / 2, self.markAnimationView.bounds.size.height / 2); 64 | 65 | // 5. 66 | UIBezierPath *maskPath = [UIBezierPath bezierPath]; 67 | int markCount = 90; 68 | CGFloat startRadian = - (225.0 / 180.0 * M_PI); 69 | CGFloat endRadian = 45.0 / 180.0 * M_PI; 70 | CGFloat perRadian = fabs(startRadian - endRadian) / markCount; 71 | for (int i = 0; i < markCount; i++) { 72 | CGFloat start = (startRadian + perRadian * i); 73 | CGFloat end = start + perRadian / 2; 74 | UIBezierPath *markPath = [UIBezierPath bezierPathWithArcCenter:centers radius:radius startAngle:start endAngle:end clockwise:YES]; 75 | [maskPath appendPath:markPath]; 76 | } 77 | 78 | CAShapeLayer *maskLayer = [CAShapeLayer layer]; 79 | maskLayer.path = maskPath.CGPath; 80 | maskLayer.strokeColor = [UIColor whiteColor].CGColor; 81 | maskLayer.lineWidth = 10.f; 82 | 83 | // 4. 84 | UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:centers radius:radius startAngle:-M_PI endAngle:M_PI clockwise:YES]; 85 | CAShapeLayer *selectLayer = [CAShapeLayer layer]; 86 | selectLayer.path = circlePath.CGPath; 87 | selectLayer.frame = self.markAnimationView.bounds; 88 | selectLayer.fillColor = [UIColor clearColor].CGColor; 89 | selectLayer.lineWidth = 10.f; 90 | selectLayer.strokeColor = BackgroundColor.CGColor; 91 | selectLayer.strokeEnd = 1.0; 92 | // 6. 93 | selectLayer.mask = maskLayer; 94 | 95 | [self.markAnimationView.layer addSublayer:selectLayer]; 96 | } 97 | @end 98 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/MarkExampleController.xib: -------------------------------------------------------------------------------- 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 | 50 | 51 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/RunAppViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RunAppViewController.h 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RunAppViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/RunAppViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RunAppViewController.m 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import "RunAppViewController.h" 10 | #import "DVSRunProgressView.h" 11 | #import "UILabel+FlickerNumber.h" 12 | 13 | 14 | #define RGBA(c,a) [UIColor colorWithRed:((c>>16)&0xFF)/256.0 green:((c>>8)&0xFF)/256.0 blue:((c)&0xFF)/256.0 alpha:a] 15 | #define RGB(c) RGBA(c,1) 16 | 17 | @interface RunAppViewController () 18 | @property (weak, nonatomic) IBOutlet DVSRunProgressView *progressView; 19 | @property (weak, nonatomic) IBOutlet UILabel *distanceLabel; 20 | 21 | @end 22 | 23 | @implementation RunAppViewController 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | self.progressView.type = DVSRunProgressViewTypeGradient; 28 | self.progressView.markCount = 45; 29 | self.progressView.duration = 1.0f; 30 | self.progressView.markHeight = 14; 31 | self.progressView.normalColor = RGB(0xE3E4E6); 32 | [self.progressView setEasyGradientColor:RGB(0x88BADE) endColor:RGB(0x80D0A9)]; 33 | } 34 | 35 | - (IBAction)runAction:(id)sender { 36 | [_distanceLabel fn_setNumber:@12.99 duration:1.0f]; 37 | [_progressView runAnimationWithPercent:0.8 completionBlock:^{ 38 | // To do something 39 | }]; 40 | } 41 | 42 | - (UIStatusBarStyle)preferredStatusBarStyle{ 43 | return UIStatusBarStyleLightContent; 44 | } 45 | @end 46 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/RunProgressExampleController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RunProgressExampleController.h 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RunProgressExampleController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DVSRunProgressView/Demo/RunProgressExampleController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RunProgressExampleController.m 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import "RunProgressExampleController.h" 10 | #import "DVSRunProgressView.h" 11 | 12 | @interface RunProgressExampleController () 13 | @property(nonatomic, strong) DVSRunProgressView *runProgressView; 14 | @end 15 | 16 | @implementation RunProgressExampleController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.view.backgroundColor = [UIColor whiteColor]; 21 | 22 | _runProgressView = [[DVSRunProgressView alloc]initWithFrame:CGRectMake(100, 180, 200, 200)]; 23 | _runProgressView.type = DVSRunProgressViewTypeNormal; 24 | _runProgressView.markCount = 45; 25 | _runProgressView.duration = 1.0f; 26 | _runProgressView.markHeight = 14; 27 | _runProgressView.selectColor = [UIColor blueColor]; 28 | 29 | [self.view addSubview:_runProgressView]; 30 | 31 | double delayInSeconds = 1.0; 32 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 33 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 34 | [_runProgressView runAnimationWithPercent:0.8]; 35 | }); 36 | 37 | } 38 | 39 | - (void)didReceiveMemoryWarning { 40 | [super didReceiveMemoryWarning]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /DVSRunProgressView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarTintParameters 32 | 33 | UINavigationBar 34 | 35 | Style 36 | UIBarStyleDefault 37 | Translucent 38 | 39 | 40 | 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | UIViewControllerBasedStatusBarAppearance 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /DVSRunProgressView/Vendor/UILabel+FlickerNumber.h: -------------------------------------------------------------------------------- 1 | // 2 | // UILabel+FlickerNumber.h 3 | // FlickerNumber 4 | // 5 | // Created by DeJohn Dong on 15-2-1. 6 | // Copyright (c) 2015年 DDKit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UILabel (FlickerNumber) 14 | 15 | /** 16 | * Flicker a number without other effects. 17 | * 18 | * @param number The number for flicker animation, can't be `nil`. 19 | */ 20 | - (void)fn_setNumber:(NSNumber *)number; 21 | 22 | /** 23 | * Flicker a number with number-formatter style. You can use the `NSNumberFormatterCurrencyStyle` number-formatter style, the number will flicker animation as `$1,023.12`. 24 | * 25 | * @param number The number for flicker animation. 26 | * @param formatter The number-formatter style. If this parameter is `nil`, the method should use the default number-formatter style -- `NSNumberFormatterDecimalStyle`, so `1000000` will be '1,000,000'. 27 | */ 28 | - (void)fn_setNumber:(NSNumber *)number 29 | formatter:(nullable NSNumberFormatter *)formatter; 30 | 31 | /** 32 | * Flicker a number in during time. 33 | * 34 | * @param number The number for flicker animation. 35 | * @param duration The flicker animation during time, can't be a minus. 36 | */ 37 | - (void)fn_setNumber:(NSNumber *)number 38 | duration:(NSTimeInterval)duration; 39 | 40 | /** 41 | * Flicker a number in during time with number-formatter style. 42 | * 43 | * @param number The number for flicker animation. 44 | * @param duration The flicker animation during time. 45 | * @param formatter The number-formatter style. 46 | */ 47 | - (void)fn_setNumber:(NSNumber *)number 48 | duration:(NSTimeInterval)duration 49 | formatter:(nullable NSNumberFormatter *)formatter; 50 | 51 | /** 52 | * Flicker a number with string-format style. like this: `Today's income: $200.00`. 53 | * 54 | * @param number The number for flicker animation. 55 | * @param formatStr The string-format String. If you set this parameter is `nil`, the method is same to `fn_setNumber:`. 56 | */ 57 | - (void)fn_setNumber:(NSNumber *)number 58 | format:(nullable NSString *)formatStr; 59 | 60 | /** 61 | * Flicker a number with string-format String & number-formatter style. 62 | * 63 | * @param number The number for flicker animation. 64 | * @param formatStr The string-format String. 65 | * @param formatter The number-formatter style. 66 | */ 67 | - (void)fn_setNumber:(NSNumber *)number 68 | format:(nullable NSString *)formatStr 69 | formatter:(nullable NSNumberFormatter *)formatter; 70 | 71 | 72 | /** 73 | * Flicker a number with attributed(s) property. 74 | * 75 | * @param number The number for flicker animation. 76 | * @param attrs The attributed number set(a dictionary OR array of dictionaries), character attributes for text. Only can attributed the number because there are no string-format String. Use this parameter the number text can be colorful and wonderful. If you set this parameter is `nil`, the same to method `fn_setNumber:`. 77 | */ 78 | - (void)fn_setNumber:(NSNumber *)number 79 | attributes:(nullable id)attrs; 80 | 81 | /** 82 | * Flicker a number with number-formatter style & attributed(s) property. 83 | * 84 | * @param number The number for flicker animation. 85 | * @param formatter The number-formatter style. 86 | * @param attrs The attributed number set(a dictionary OR array of dictionaries). 87 | */ 88 | - (void)fn_setNumber:(NSNumber *)number 89 | formatter:(nullable NSNumberFormatter *)formatter 90 | attributes:(nullable id)attrs; 91 | 92 | /** 93 | * Flicker a number with string-format String & attributed(s) property. 94 | * 95 | * @param number The number for flicker animation. 96 | * @param formatStr The string-format String. 97 | * @param attrs The attributed string set(a dictionary OR array of dictionaries). You can attributed(s) the number or string-format String. 98 | */ 99 | - (void)fn_setNumber:(NSNumber *)number 100 | format:(nullable NSString *)formatStr 101 | attributes:(nullable id)attrs; 102 | 103 | /** 104 | * Flicker a number in dafault during time(1.0s) with all effects. 105 | * 106 | * @param number The number for flicker animation. 107 | * @param formatStr The string-format String. 108 | * @param formatter The number-formatter style. 109 | * @param attrs The attributed string set(a dictionary OR array of dictionaries).You can attributed(s) the number or string-format String. 110 | */ 111 | - (void)fn_setNumber:(NSNumber *)number 112 | format:(nullable NSString *)formatStr 113 | formatter:(nullable NSNumberFormatter *)formatter 114 | attributes:(nullable id)attrs; 115 | 116 | /** 117 | * Flicker a number in during time with string-format String. 118 | * 119 | * @param number The number for flicker animation. 120 | * @param duration The flicker animation during time. 121 | * @param formatStr The string-format String. 122 | */ 123 | - (void)fn_setNumber:(NSNumber *)number 124 | duration:(NSTimeInterval)duration 125 | format:(nullable NSString *)formatStr; 126 | 127 | /** 128 | * Flicker a number in during time with string-format String & number-formatter style. 129 | * 130 | * @param number The number for flicker animation. 131 | * @param duration The flicker animation during time. 132 | * @param formatStr The string-format String. 133 | * @param formatter The number-formatter style. 134 | */ 135 | - (void)fn_setNumber:(NSNumber *)number 136 | duration:(NSTimeInterval)duration 137 | format:(nullable NSString *)formatStr 138 | formatter:(nullable NSNumberFormatter *)formatter; 139 | 140 | /** 141 | * Flicker a number in during time with attributed(s) property. 142 | * 143 | * @param number The number for flicker animation. 144 | * @param duration The flicker animation during time. 145 | * @param attrs The attributed number set(a dictionary OR array of dictionaries). 146 | */ 147 | - (void)fn_setNumber:(NSNumber *)number 148 | duration:(NSTimeInterval)duration 149 | attributes:(nullable id)attrs; 150 | 151 | /** 152 | * Flicker a number in during time with attributed(s) property of number & number-formatter style. 153 | * 154 | * @param number The number for flicker animation. 155 | * @param duration The flicker animation during time. 156 | * @param formatter The number-formatter style. 157 | * @param attrs The attributed number set(a dictionary OR array of dictionaries). 158 | */ 159 | - (void)fn_setNumber:(NSNumber *)number 160 | duration:(NSTimeInterval)duration 161 | formatter:(nullable NSNumberFormatter *)formatter 162 | attributes:(nullable id)attrs; 163 | 164 | /** 165 | * Flicker a number in during time with effects except number-formatter style. 166 | * 167 | * @param number The number for flicker animation. 168 | * @param duration The flicker animation during time. 169 | * @param formatStr The string-format String. 170 | * @param attrs The attributed string set(a dictionary OR array of dictionaries). You can set string-format String OR number attributes both. 171 | */ 172 | - (void)fn_setNumber:(NSNumber *)number 173 | duration:(NSTimeInterval)duration 174 | format:(nullable NSString *)formatStr 175 | attributes:(nullable id)attrs; 176 | 177 | /** 178 | * Flicker a number in during time with all the effects. You can attributed(s) the number or string-format String. You also can set the number number-fomatter style. 179 | * 180 | * @param number The number for flicker animation. 181 | * @param duration The flicker animation during time. 182 | * @param formatStr The string-format String. 183 | * @param formatter The number-formatter style. 184 | * @param attrs The attributed string set(a dictionary OR array of dictionaries). 185 | */ 186 | - (void)fn_setNumber:(NSNumber *)number 187 | duration:(NSTimeInterval)duration 188 | format:(nullable NSString *)formatStr 189 | numberFormatter:(nullable NSNumberFormatter *)formatter 190 | attributes:(nullable id)attrs; 191 | 192 | @end 193 | 194 | @interface UILabel (FlickerNumberDeprecated) 195 | 196 | #pragma clang diagnostic push 197 | #pragma clang diagnostic ignored "-Wnonnull" 198 | 199 | - (void)dd_setNumber:(NSNumber *)number __deprecated_msg("Use `fn_setNumber:`"); 200 | - (void)dd_setNumber:(NSNumber *)number formatter:(NSNumberFormatter *)formatter __deprecated_msg("Use `fn_setNumber:formatter:`"); 201 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration __deprecated_msg("Use `fn_setNumber:duration:`"); 202 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration formatter:(NSNumberFormatter *)formatter __deprecated_msg("Use `fn_setNumber:duration:formatter:"); 203 | - (void)dd_setNumber:(NSNumber *)number format:(NSString *)formatStr __deprecated_msg("Use `fn_setNumber:format:`"); 204 | - (void)dd_setNumber:(NSNumber *)number format:(NSString *)formatStr formatter:(NSNumberFormatter *)formatter __deprecated_msg("Use `fn_setNumber:format:formatter:`"); 205 | - (void)dd_setNumber:(NSNumber *)number attributes:(id)attrs __deprecated_msg("Use `fn_setNumber:attributes:`"); 206 | - (void)dd_setNumber:(NSNumber *)number formatter:(NSNumberFormatter *)formatter attributes:(id)attrs __deprecated_msg("Use `fn_setNumber:formatter:attributes:`"); 207 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr __deprecated_msg("Use `fn_setNumber:duration:format:`"); 208 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr formatter:(NSNumberFormatter *)formatter __deprecated_msg("Use `fn_setNumber:duration:format:formatter:`"); 209 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration attributes:(id)attrs __deprecated_msg("Use `fn_setNumber:duration:attributes:`"); 210 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration formatter:(NSNumberFormatter *)formatter attributes:(id)attrs __deprecated_msg("Use `fn_setNumber:duration:formatter:attributes:`"); 211 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr attributes:(id)attrs __deprecated_msg("Use `fn_setNumber:duration:format:attributes:`"); 212 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr numberFormatter:(NSNumberFormatter *)formatter attributes:(id)attrs __deprecated_msg("Use `fn_setNumber:duration:format:formatter:attributes:`"); 213 | 214 | #pragma clang diagnostic pop 215 | 216 | @end 217 | 218 | @interface NSDictionary(FlickerNumber) 219 | 220 | /** 221 | * Create an attribute texts dictionary, like the NSAttributedString. 222 | * 223 | * @param attribute The attributed text of the dictionary. 224 | * @param range The range of the attributed text. 225 | * 226 | * @return Dictionary of attributed text. 227 | */ 228 | + (instancetype)fn_dictionaryWithAttribute:(NSDictionary *)attribute range:(NSRange)range; 229 | 230 | @end 231 | 232 | @interface NSDictionary (FlickerNumberDeprecated) 233 | 234 | + (instancetype)dictionaryWithAttribute:(NSDictionary *)attribute range:(NSRange)range __deprecated_msg("Use `fn_dictionaryWithAttribute:range:`"); 235 | 236 | @end 237 | 238 | NS_ASSUME_NONNULL_END 239 | 240 | -------------------------------------------------------------------------------- /DVSRunProgressView/Vendor/UILabel+FlickerNumber.m: -------------------------------------------------------------------------------- 1 | // 2 | // UILabel+FlickerNumber.m 3 | // FlickerNumber 4 | // 5 | // Created by DeJohn Dong on 15-2-1. 6 | // Copyright (c) 2015年 DDKit. All rights reserved. 7 | // 8 | 9 | #import "UILabel+FlickerNumber.h" 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | #define DDRangeIntegerKey @"RangeKey" 15 | #define DDMultipleKey @"MultipleKey" 16 | #define DDBeginNumberKey @"BeginNumberKey" 17 | #define DDEndNumberKey @"EndNumberKey" 18 | #define DDResultNumberKey @"ResultNumberKey" 19 | 20 | #define DDAttributeKey @"AttributeKey" 21 | #define DDFormatKey @"FormatStringKey" 22 | 23 | #define DDFrequency 1.0/30.0f 24 | 25 | #define DDDictArrtributeKey @"attribute" 26 | #define DDDictRangeKey @"range" 27 | 28 | @interface UILabel () 29 | 30 | @property (nonatomic, strong, readwrite) NSNumber *flickerNumber; 31 | @property (nonatomic, strong, readwrite, nullable) NSNumberFormatter *flickerNumberFormatter; 32 | @property (nonatomic, strong, readwrite, nullable) NSTimer *currentTimer; 33 | 34 | @end 35 | 36 | @implementation UILabel (FlickerNumber) 37 | 38 | #pragma mark - runtime methods 39 | 40 | - (void)setFlickerNumber:(NSNumber *)flickerNumber { 41 | objc_setAssociatedObject(self, @selector(flickerNumber), flickerNumber, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 42 | } 43 | 44 | - (NSNumber *)flickerNumber { 45 | return objc_getAssociatedObject(self, _cmd); 46 | } 47 | 48 | - (void)setFlickerNumberFormatter:(nullable NSNumberFormatter *)flickerNumberFormatter { 49 | objc_setAssociatedObject(self, @selector(flickerNumberFormatter), flickerNumberFormatter, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 50 | } 51 | 52 | - (nullable NSNumberFormatter *)flickerNumberFormatter { 53 | return objc_getAssociatedObject(self, _cmd); 54 | } 55 | 56 | - (void)setCurrentTimer:(nullable NSTimer *)currentTimer { 57 | objc_setAssociatedObject(self, @selector(currentTimer), currentTimer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 58 | } 59 | 60 | - (nullable NSTimer *)currentTimer { 61 | return objc_getAssociatedObject(self, _cmd); 62 | } 63 | 64 | #pragma mark - flicker methods(public) 65 | 66 | //Method #1 67 | - (void)fn_setNumber:(NSNumber *)number { 68 | [self fn_setNumber:number format:nil]; 69 | } 70 | 71 | //Method #2 72 | - (void)fn_setNumber:(NSNumber *)number formatter:(nullable NSNumberFormatter *)formatter { 73 | [self fn_setNumber:number formatter:formatter attributes:nil]; 74 | } 75 | 76 | //Method #3 77 | - (void)fn_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration { 78 | [self fn_setNumber:number duration:duration format:nil attributes:nil]; 79 | } 80 | 81 | //Method #4 82 | - (void)fn_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration formatter:(nullable NSNumberFormatter *)formatter{ 83 | [self fn_setNumber:number duration:duration formatter:formatter attributes:nil]; 84 | } 85 | 86 | //Method #5 87 | - (void)fn_setNumber:(NSNumber *)number format:(nullable NSString *)formatStr { 88 | [self fn_setNumber:number format:formatStr attributes:nil]; 89 | } 90 | 91 | //Method #6 92 | - (void)fn_setNumber:(NSNumber *)number format:(nullable NSString *)formatStr formatter:(nullable NSNumberFormatter *)formatter { 93 | [self fn_setNumber:number format:formatStr formatter:formatter attributes:nil]; 94 | } 95 | 96 | //Method #7 97 | - (void)fn_setNumber:(NSNumber *)number attributes:(nullable id)attrs { 98 | [self fn_setNumber:number format:nil attributes:attrs]; 99 | } 100 | 101 | //Method #8 102 | - (void)fn_setNumber:(NSNumber *)number formatter:(nullable NSNumberFormatter *)formatter attributes:(nullable id)attrs { 103 | [self fn_setNumber:number duration:1.0 format:nil numberFormatter:formatter attributes:attrs]; 104 | } 105 | 106 | //Method #9 107 | - (void)fn_setNumber:(NSNumber *)number format:(nullable NSString *)formatStr attributes:(nullable id)attrs { 108 | [self fn_setNumber:number duration:1.0 format:formatStr attributes:attrs]; 109 | } 110 | 111 | //Method #10 112 | - (void)fn_setNumber:(NSNumber *)number format:(nullable NSString *)formatStr formatter:(nullable NSNumberFormatter *)formatter attributes:(nullable id)attrs { 113 | if(!formatter) { 114 | formatter = [self defaultFormatter]; 115 | } 116 | [self fn_setNumber:number duration:1.0 format:formatStr numberFormatter:formatter attributes:attrs]; 117 | } 118 | 119 | //Method #11 120 | - (void)fn_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(nullable NSString *)formatStr { 121 | [self fn_setNumber:number duration:duration format:formatStr attributes:nil]; 122 | } 123 | 124 | //Method #12 125 | - (void)fn_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(nullable NSString *)formatStr formatter:(nullable NSNumberFormatter *)formatter { 126 | if(!formatter) 127 | formatter = [self defaultFormatter]; 128 | [self fn_setNumber:number duration:duration format:formatStr formatter:formatter]; 129 | } 130 | 131 | //Method #13 132 | - (void)fn_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration attributes:(nullable id)attrs { 133 | [self fn_setNumber:number duration:duration format:nil attributes:attrs]; 134 | } 135 | 136 | //Method #14 137 | - (void)fn_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration formatter:(nullable NSNumberFormatter *)formatter attributes:(nullable id)attrs { 138 | if(!formatter) 139 | formatter = [self defaultFormatter]; 140 | [self fn_setNumber:number duration:duration format:nil numberFormatter:formatter attributes:attrs]; 141 | } 142 | 143 | //Method #15 144 | - (void)fn_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(nullable NSString *)formatStr attributes:(nullable id)attrs { 145 | [self fn_setNumber:number duration:duration format:formatStr numberFormatter:nil attributes:attrs]; 146 | } 147 | 148 | //Method #16 149 | - (void)fn_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(nullable NSString *)formatStr numberFormatter:(nullable NSNumberFormatter *)formatter attributes:(nullable id)attrs { 150 | /** 151 | * check the number type 152 | */ 153 | NSAssert([number isKindOfClass:[NSNumber class]], @"Number Type is not matched , exit"); 154 | if(![number isKindOfClass:[NSNumber class]]) { 155 | self.text = [NSString stringWithFormat:@"%@",number]; 156 | return; 157 | } 158 | 159 | /* limit duration is postive number and it is large than 0.3 , fixed the issue#1--https://github.com/openboy2012/FlickerNumber/issues/1 */ 160 | duration = fabs(duration) < 0.3 ? 0.3 : fabs(duration); 161 | 162 | [self.currentTimer invalidate]; 163 | self.currentTimer = nil; 164 | 165 | //initialize useinfo dict 166 | NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:0]; 167 | 168 | if(formatStr) 169 | [userInfo setObject:formatStr forKey:DDFormatKey]; 170 | 171 | [userInfo setObject:number forKey:DDResultNumberKey]; 172 | 173 | //initialize variables 174 | long long beginNumber = 0; 175 | [userInfo setObject:@(beginNumber) forKey:DDBeginNumberKey]; 176 | self.flickerNumber = @0; 177 | unsigned long long endNumber = [number unsignedLongLongValue]; 178 | 179 | //get multiple if number is double type 180 | int multiple = [self getTheMultipleFromNumber:number formatString:formatStr]; 181 | if (multiple > 0) 182 | endNumber = [number doubleValue] * multiple; 183 | 184 | //check the number if out of bounds the unsigned int length 185 | if (endNumber >= INT64_MAX) { 186 | self.text = [NSString stringWithFormat:@"%@",number]; 187 | return; 188 | } 189 | 190 | [userInfo setObject:@(multiple) forKey:DDMultipleKey]; 191 | [userInfo setObject:@(endNumber) forKey:DDEndNumberKey]; 192 | if ((endNumber * DDFrequency)/duration < 1) { 193 | duration = duration * 0.3; 194 | } 195 | [userInfo setObject:@((endNumber * DDFrequency)/duration) forKey:DDRangeIntegerKey]; 196 | 197 | if(attrs) 198 | [userInfo setObject:attrs forKey:DDAttributeKey]; 199 | 200 | self.flickerNumberFormatter = nil; 201 | if(formatter) 202 | self.flickerNumberFormatter = formatter; 203 | 204 | self.currentTimer = [NSTimer scheduledTimerWithTimeInterval:DDFrequency target:self selector:@selector(flickerAnimation:) userInfo:userInfo repeats:YES]; 205 | [[NSRunLoop currentRunLoop] addTimer:self.currentTimer forMode:NSRunLoopCommonModes]; 206 | } 207 | 208 | #pragma mark - private methods 209 | /** 210 | * Flicker number animation implemetation method. 211 | * 212 | * @param timer The schedule timer, the time interval decide the number flicker counts. 213 | */ 214 | - (void)flickerAnimation:(NSTimer *)timer { 215 | /** 216 | * check the rangeNumber if more than 1.0, fixed the issue#2--https://github.com/openboy2012/FlickerNumber/issues/2 217 | */ 218 | if ([timer.userInfo[DDRangeIntegerKey] floatValue] >= 1.0) { 219 | long long rangeInteger = [timer.userInfo[DDRangeIntegerKey] longLongValue]; 220 | self.flickerNumber = @([self.flickerNumber longLongValue] + rangeInteger); 221 | } else { 222 | float rangeInteger = [timer.userInfo[DDRangeIntegerKey] floatValue]; 223 | self.flickerNumber = @([self.flickerNumber floatValue] + rangeInteger); 224 | } 225 | 226 | 227 | int multiple = [timer.userInfo[DDMultipleKey] intValue]; 228 | if (multiple > 0) { 229 | [self floatNumberAnimation:timer multiple:multiple]; 230 | } else { 231 | NSString *formatStr = timer.userInfo[DDFormatKey]?:(self.flickerNumberFormatter?@"%@":@"%.0f"); 232 | self.text = [self finalString:@([self.flickerNumber longLongValue]) stringFormat:formatStr numberFormatter:self.flickerNumberFormatter]; 233 | 234 | if (timer.userInfo[DDAttributeKey]) { 235 | [self addTextAttributes:timer.userInfo[DDAttributeKey]]; 236 | } 237 | 238 | if ([self.flickerNumber longLongValue] >= [timer.userInfo[DDEndNumberKey] longLongValue]) { 239 | self.text = [self finalString:timer.userInfo[DDResultNumberKey] stringFormat:formatStr numberFormatter:self.flickerNumberFormatter]; 240 | if (timer.userInfo[DDAttributeKey]) { 241 | [self addTextAttributes:timer.userInfo[DDAttributeKey]]; 242 | } 243 | [timer invalidate]; 244 | } 245 | } 246 | } 247 | 248 | /** 249 | * Float number handle method. 250 | * 251 | * @param timer timer 252 | * @param multiple The number's multiple. 253 | */ 254 | - (void)floatNumberAnimation:(NSTimer *)timer multiple:(int)multiple { 255 | NSString *formatStr = timer.userInfo[DDFormatKey] ?: (self.flickerNumberFormatter ? @"%@" : [NSString stringWithFormat:@"%%.%df",(int)log10(multiple)]); 256 | self.text = [self finalString:@([self.flickerNumber doubleValue]/multiple) stringFormat:formatStr numberFormatter:self.flickerNumberFormatter]; 257 | if (timer.userInfo[DDAttributeKey]) { 258 | [self addTextAttributes:timer.userInfo[DDAttributeKey]]; 259 | } 260 | if ([self.flickerNumber longLongValue] >= [timer.userInfo[DDEndNumberKey] longLongValue]) { 261 | self.text = [self finalString:timer.userInfo[DDResultNumberKey] stringFormat:formatStr numberFormatter:self.flickerNumberFormatter]; 262 | if (timer.userInfo[DDAttributeKey]) { 263 | [self addTextAttributes:timer.userInfo[DDAttributeKey]]; 264 | } 265 | [timer invalidate]; 266 | } 267 | } 268 | 269 | /** 270 | * The attributed(s) text handle methods 271 | * 272 | * @param attributes The attributed property, it's a attributed dictionary OR array of attributed dictionaries. 273 | */ 274 | - (void)addTextAttributes:(id)attributes { 275 | if ([attributes isKindOfClass:[NSDictionary class]]) { 276 | NSRange range = [attributes[DDDictRangeKey] rangeValue]; 277 | [self addAttribute:attributes[DDDictArrtributeKey] range:range]; 278 | } else if([attributes isKindOfClass:[NSArray class]]) { 279 | for (NSDictionary *attribute in attributes) { 280 | NSRange range = [attribute[DDDictRangeKey] rangeValue]; 281 | [self addAttribute:attribute[DDDictArrtributeKey] range:range]; 282 | } 283 | } 284 | } 285 | 286 | /** 287 | * Add attributed property into the number text OR string-format text. 288 | * 289 | * @param attri The attributed of the text 290 | * @param range The range of the attributed property 291 | */ 292 | - (void)addAttribute:(NSDictionary *)attri 293 | range:(NSRange)range { 294 | NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText]; 295 | // handler the out range exception 296 | if(range.location + range.length <= str.length){ 297 | [str addAttributes:attri range:range]; 298 | } 299 | self.attributedText = str; 300 | } 301 | 302 | /** 303 | * Get muliple from number 304 | * 305 | * @param number past number 306 | * 307 | * @return mulitple 308 | */ 309 | - (int)getTheMultipleFromNumber:(NSNumber *)number 310 | formatString:(NSString *)formatStr { 311 | if([formatStr rangeOfString:@"%@"].location == NSNotFound) { 312 | if([formatStr rangeOfString:@"%d"].location != NSNotFound) { 313 | return 0; 314 | } 315 | formatStr = [self regexNumberFormat:formatStr]; 316 | NSString *formatNumberString = [NSString stringWithFormat:formatStr,[number floatValue]]; 317 | if ([formatNumberString rangeOfString:@"."].location != NSNotFound) { 318 | NSUInteger length = [[formatNumberString substringFromIndex:[formatNumberString rangeOfString:@"."].location + 1] length]; 319 | float padding = log10f(length < 6 ? length:6); 320 | number = @([formatNumberString floatValue] + padding); 321 | } 322 | } 323 | 324 | NSString *str = [NSString stringWithFormat:@"%@",number]; 325 | if([str rangeOfString:@"."].location != NSNotFound) { 326 | NSUInteger length = [[str substringFromIndex:[str rangeOfString:@"."].location +1] length]; 327 | // Max Multiple is 6 328 | return length >= 6 ? pow(10, 6): pow(10, (int)length); 329 | } 330 | return 0; 331 | } 332 | 333 | /** 334 | * Get the number string from number-formatter style. 335 | * 336 | * @param number The result number. 337 | * @param formattor The number-formatter style. 338 | * 339 | * @return The number string. 340 | */ 341 | - (NSString *)stringFromNumber:(NSNumber *)number 342 | numberFormatter:(NSNumberFormatter *)formattor { 343 | if(!formattor) { 344 | formattor = [[NSNumberFormatter alloc] init]; 345 | formattor.formatterBehavior = NSNumberFormatterBehavior10_4; 346 | formattor.numberStyle = NSNumberFormatterDecimalStyle; 347 | } 348 | return [formattor stringFromNumber:number]; 349 | } 350 | 351 | /** 352 | * The final-string of each frame of flicker animation. 353 | * 354 | * @param number The result number. 355 | * @param formatStr The string-format String. 356 | * @param formatter The number-formatter style. 357 | * 358 | * @return The final string. 359 | */ 360 | - (NSString *)finalString:(NSNumber *)number 361 | stringFormat:(NSString *)formatStr 362 | numberFormatter:(NSNumberFormatter *)formatter { 363 | NSString *finalString = nil; 364 | if (formatter) { 365 | NSAssert([formatStr rangeOfString:@"%@"].location != NSNotFound, @"The string format type is not matched. Please check your format type if it's not `%%@`. "); 366 | finalString = [NSString stringWithFormat:formatStr,[self stringFromNumber:number numberFormatter:formatter]]; 367 | } else { 368 | NSAssert([formatStr rangeOfString:@"%@"].location == NSNotFound, @"The string format type is not matched. Please check your format type if it's `%%@`. "); 369 | // fixed the bug if use the `%d` format string. 370 | if ([formatStr rangeOfString:@"%d"].location == NSNotFound) 371 | { 372 | finalString = [NSString stringWithFormat:formatStr,[number doubleValue]]; 373 | } 374 | else 375 | { 376 | finalString = [NSString stringWithFormat:formatStr,[number longLongValue]]; 377 | } 378 | } 379 | return finalString; 380 | } 381 | 382 | /** 383 | * Get the decimal style number as default number-formatter style. 384 | * 385 | * @return The number-foramtter style. 386 | */ 387 | - (NSNumberFormatter *)defaultFormatter { 388 | NSNumberFormatter *formattor = [[NSNumberFormatter alloc] init]; 389 | formattor.formatterBehavior = NSNumberFormatterBehavior10_4; 390 | formattor.numberStyle = NSNumberFormatterDecimalStyle; 391 | return formattor; 392 | } 393 | 394 | /** 395 | * Get the format string use regex feature. This methods to handle the number is an integer number but it should string format as a float number, like this `self.text = [NSString stringFormat:@"%f",1234]`, it's show `1234.000000`. 396 | * 397 | * @param formatString The origin string 398 | * 399 | * @return The string-format String. 400 | */ 401 | - (NSString *)regexNumberFormat:(NSString *)formatString { 402 | NSError *regexError = nil; 403 | NSRegularExpression *regex = 404 | [NSRegularExpression regularExpressionWithPattern:@"^%((\\d+.\\d+)|(\\d+).|(.\\d+))f$" 405 | options:NSRegularExpressionCaseInsensitive 406 | error:®exError]; 407 | if (!regexError) { 408 | NSTextCheckingResult *match = [regex firstMatchInString:formatString 409 | options:0 410 | range:NSMakeRange(0, [formatString length])]; 411 | if (match) { 412 | NSString *result = [formatString substringWithRange:match.range]; 413 | return result; 414 | } 415 | } else { 416 | NSLog(@"error - %@", regexError); 417 | } 418 | return @"%f"; 419 | } 420 | 421 | @end 422 | 423 | @implementation UILabel (FlickerNumberDeprecated) 424 | 425 | - (void)dd_setNumber:(NSNumber *)number { 426 | [self fn_setNumber:number format:nil]; 427 | } 428 | 429 | - (void)dd_setNumber:(NSNumber *)number formatter:(NSNumberFormatter *)formatter { 430 | [self fn_setNumber:number format:nil formatter:formatter]; 431 | } 432 | 433 | - (void)dd_setNumber:(NSNumber *)number format:(NSString *)formatStr { 434 | [self fn_setNumber:number format:formatStr]; 435 | } 436 | 437 | - (void)dd_setNumber:(NSNumber *)number format:(NSString *)formatStr formatter:(NSNumberFormatter *)formatter { 438 | [self fn_setNumber:number format:formatStr formatter:formatter]; 439 | } 440 | 441 | - (void)dd_setNumber:(NSNumber *)number attributes:(id)attrs { 442 | [self fn_setNumber:number attributes:attrs]; 443 | } 444 | 445 | - (void)dd_setNumber:(NSNumber *)number formatter:(NSNumberFormatter *)formatter attributes:(id)attrs { 446 | [self fn_setNumber:number formatter:formatter attributes:attrs]; 447 | } 448 | 449 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr { 450 | [self fn_setNumber:number duration:duration format:formatStr]; 451 | } 452 | 453 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr numberFormatter:(NSNumberFormatter *)formatter { 454 | [self fn_setNumber:number duration:duration format:formatStr formatter:formatter]; 455 | } 456 | 457 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration { 458 | [self fn_setNumber:number duration:duration]; 459 | } 460 | 461 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration formatter:(NSNumberFormatter *)formatter { 462 | [self fn_setNumber:number duration:duration formatter:formatter]; 463 | } 464 | 465 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration attributes:(id)attrs { 466 | [self fn_setNumber:number duration:duration attributes:attrs]; 467 | } 468 | 469 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr formatter:(NSNumberFormatter *)formatter { 470 | [self fn_setNumber:number duration:duration format:formatStr formatter:formatter]; 471 | } 472 | 473 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration formatter:(NSNumberFormatter *)formatter attributes:(id)attrs { 474 | [self fn_setNumber:number duration:duration formatter:formatter attributes:attrs]; 475 | } 476 | 477 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr attributes:(id)attrs { 478 | [self fn_setNumber:number duration:duration format:formatStr attributes:attrs]; 479 | } 480 | 481 | - (void)dd_setNumber:(NSNumber *)number duration:(NSTimeInterval)duration format:(NSString *)formatStr numberFormatter:(NSNumberFormatter *)formatter attributes:(id)attrs { 482 | [self fn_setNumber:number duration:duration format:formatStr numberFormatter:formatter attributes:attrs]; 483 | } 484 | 485 | @end 486 | 487 | @implementation NSDictionary (FlickerNumber) 488 | 489 | + (instancetype)fn_dictionaryWithAttribute:(NSDictionary *)attribute range:(NSRange)range { 490 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:0]; 491 | [dict setObject:attribute forKey:DDDictArrtributeKey]; 492 | [dict setObject:[NSValue valueWithRange:range] forKey:DDDictRangeKey]; 493 | return dict; 494 | } 495 | 496 | @end 497 | 498 | @implementation NSDictionary (FlickerNumberDeprecated) 499 | 500 | + (instancetype)dictionaryWithAttribute:(NSDictionary *)attribute range:(NSRange)range { 501 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:0]; 502 | [dict setObject:attribute forKey:DDDictArrtributeKey]; 503 | [dict setObject:[NSValue valueWithRange:range] forKey:DDDictRangeKey]; 504 | return dict; 505 | } 506 | 507 | @end 508 | 509 | NS_ASSUME_NONNULL_END 510 | 511 | -------------------------------------------------------------------------------- /DVSRunProgressView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DVSRunProgressView 4 | // 5 | // Created by DevinShine on 17/1/7. 6 | // Copyright © 2017年 DevinShine. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 DevinShine 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DVSRunProgressView 2 | 3 | Inspired by the [works](https://dribbble.com/shots/3186995-THe-application-of-movement) of [Xerxes](https://dribbble.com/W_e_i) 4 | 5 | 可以阅读我的文章了解具体制作思路。[Read my article](http://www.jianshu.com/p/db242a4a5038) 6 | 7 | ![6](http://o6lbfzf4d.bkt.clouddn.com/2017-01-07-6.gif) 8 | 9 | 10 | 11 | Features 12 | ============== 13 | - Support pure color and gradient color. 14 | - Can be used in Interface Builder. 15 | 16 | Requirements 17 | ============== 18 | - iOS 9.0+ 19 | - Xcode 8 20 | 21 | Usage 22 | ============== 23 | 24 | - By coding. 25 | 26 | ```objc 27 | DVSRunProgressView *runProgressView; 28 | runProgressView = [[DVSRunProgressView alloc]initWithFrame:CGRectMake(100, 180, 200, 200)]; 29 | runProgressView.type = DVSRunProgressViewTypeNormal; 30 | runProgressView.markCount = 45; 31 | runProgressView.duration = 1.0f; 32 | runProgressView.markHeight = 14; 33 | runProgressView.selectColor = [UIColor blueColor]; 34 | 35 | double delayInSeconds = 1.0; 36 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 37 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 38 | [runProgressView runAnimationWithPercent:0.8]; 39 | }); 40 | ``` 41 | 42 | - By using Storyboard or XIB. 43 | ![](http://o6lbfzf4d.bkt.clouddn.com/2017-01-07-10.png) 44 | 45 | 46 | Customize 47 | ============== 48 | 49 | ```objc 50 | /** The basic duration of the object. Defaults to 1. */ 51 | @property(nonatomic, assign) IBInspectable CFTimeInterval duration; 52 | 53 | /** The start angle. (e.g. 225) */ 54 | @property(nonatomic, assign) IBInspectable CGFloat startAngle; 55 | 56 | /** The end angle. (e.g. 45) */ 57 | @property(nonatomic, assign) IBInspectable CGFloat endAngle; 58 | 59 | /** The radius offset. */ 60 | @property(nonatomic, assign) IBInspectable CGFloat circleRadiusOffset; 61 | 62 | /** The maximum number of objects the mark should hold. */ 63 | @property(nonatomic, assign) IBInspectable NSUInteger markCount; 64 | 65 | /** The mark height */ 66 | @property(nonatomic, assign) IBInspectable CGFloat markHeight; 67 | 68 | /** The normal color */ 69 | @property(nonatomic, strong) IBInspectable UIColor *normalColor; 70 | 71 | /** The select color */ 72 | @property(nonatomic, strong) IBInspectable UIColor *selectColor; 73 | 74 | /** The progress type */ 75 | @property(nonatomic, assign) DVSRunProgressViewType type; 76 | 77 | /** The color array in gradient mode, which is equivalent to the colors of CAGradientLayer */ 78 | @property(nonatomic, nullable, copy) NSArray *gradientColors; 79 | 80 | /** The array of positions in the gradient mode, which is equivalent to the locations of the CAGradientLayer */ 81 | @property(nonatomic, nullable, copy) NSArray *gradientLocations; 82 | 83 | /** The startPoint in gradient mode, which is equivalent to the startPoint of CAGradientLayer */ 84 | @property(nonatomic, assign) IBInspectable CGPoint gradientStartPoint; 85 | 86 | /** The endPoint in gradient mode, which is equivalent to the endPoint of CAGradientLayer */ 87 | @property(nonatomic, assign) IBInspectable CGPoint gradientEndPoint; 88 | ``` 89 | 90 | Demo 91 | ============== 92 | There is a demo project added to this repository, so you can see how it works. 93 | 94 | License 95 | ============== 96 | DVSRunProgressView is provided under the MIT license. See LICENSE file for details. 97 | 98 | --------------------------------------------------------------------------------