├── .gitignore ├── .travis.yml ├── Assets ├── applewatch1.png └── example1.png ├── ESArcProgressView.podspec ├── ESArcProgressView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── ESArcProgressView.xcscheme ├── ESArcProgressView.xcworkspace └── contents.xcworkspacedata ├── ESArcProgressView ├── ESArcProgressView+Animations.h ├── ESArcProgressView+Animations.m ├── ESArcProgressView.h ├── ESArcProgressViewCore.h ├── ESArcProgressViewCore.m ├── ESMultipleArcProgressView.h ├── ESMultipleArcProgressView.m └── Info.plist ├── ESArcProgressViewTests ├── ESArcProgressViewTests.m └── Info.plist ├── LICENSE ├── Podfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | xcode_workspace: ESArcProgressView.xcworkspace 3 | xcode_scheme: ESArcProgressView 4 | xcode_sdk: iphonesimulator8.1 5 | -------------------------------------------------------------------------------- /Assets/applewatch1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-sites/ESArcProgressView/6191efed1b83532677b3d2ed95256c351e6f759e/Assets/applewatch1.png -------------------------------------------------------------------------------- /Assets/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e-sites/ESArcProgressView/6191efed1b83532677b3d2ed95256c351e6f759e/Assets/example1.png -------------------------------------------------------------------------------- /ESArcProgressView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "ESArcProgressView" 4 | s.version = "1.6.4" 5 | s.platform = :ios, '7.0' 6 | s.requires_arc = true 7 | s.author = { "bvkuijck" => "Bas van Kuijck " } 8 | s.license = { :type => "MIT", :file => "LICENSE" } 9 | s.summary = "A progress view to be used within Apple Watch projects." 10 | s.source = { :git => "https://github.com/e-sites/ESArcProgressView.git", :tag => s.version.to_s } 11 | s.homepage = "https://github.com/e-sites/ESArcProgressView" 12 | s.source_files = 'ESArcProgressView/ESArcProgressView.h' 13 | s.public_header_files = 'ESArcProgressView/*.h' 14 | 15 | s.subspec 'Core' do |ss| 16 | ss.source_files = 'ESArcProgressView/ESArcProgressViewCore.{h,m}' 17 | s.frameworks = 'QuartzCore' 18 | end 19 | 20 | s.subspec 'Multiple' do |ss| 21 | ss.dependency 'ESArcProgressView/Core' 22 | ss.source_files = 'ESArcProgressView/ESMultipleArcProgressView.{h,m}' 23 | end 24 | 25 | s.subspec 'Animations' do |ss| 26 | ss.dependency 'AHEasing', '~> 1.2' 27 | ss.dependency 'ESArcProgressView/Core' 28 | ss.source_files = 'ESArcProgressView/ESArcProgressView+Animations.{h,m}' 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /ESArcProgressView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DF444D8F1AAEFF3900BB2721 /* ESArcProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF444D831AAEFF3900BB2721 /* ESArcProgressView.framework */; }; 11 | DF444D961AAEFF3900BB2721 /* ESArcProgressViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DF444D951AAEFF3900BB2721 /* ESArcProgressViewTests.m */; }; 12 | DF444DA81AAF08EC00BB2721 /* ESArcProgressView.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = DF444D831AAEFF3900BB2721 /* ESArcProgressView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXContainerItemProxy section */ 16 | DF444D901AAEFF3900BB2721 /* PBXContainerItemProxy */ = { 17 | isa = PBXContainerItemProxy; 18 | containerPortal = DF444D7A1AAEFF3900BB2721 /* Project object */; 19 | proxyType = 1; 20 | remoteGlobalIDString = DF444D821AAEFF3900BB2721; 21 | remoteInfo = ESArcProgressView; 22 | }; 23 | /* End PBXContainerItemProxy section */ 24 | 25 | /* Begin PBXCopyFilesBuildPhase section */ 26 | DF444DA71AAF08E000BB2721 /* CopyFiles */ = { 27 | isa = PBXCopyFilesBuildPhase; 28 | buildActionMask = 2147483647; 29 | dstPath = ""; 30 | dstSubfolderSpec = 10; 31 | files = ( 32 | DF444DA81AAF08EC00BB2721 /* ESArcProgressView.framework in CopyFiles */, 33 | ); 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXCopyFilesBuildPhase section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | DF444D831AAEFF3900BB2721 /* ESArcProgressView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ESArcProgressView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | DF444D8E1AAEFF3900BB2721 /* ESArcProgressViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ESArcProgressViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | DF444D941AAEFF3900BB2721 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 42 | DF444D951AAEFF3900BB2721 /* ESArcProgressViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ESArcProgressViewTests.m; sourceTree = ""; }; 43 | DF7ECB631B0226B100B28386 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 44 | DF7ECB641B0226B100B28386 /* Pods.release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | DF444D7F1AAEFF3900BB2721 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | DF444D8B1AAEFF3900BB2721 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | DF444D8F1AAEFF3900BB2721 /* ESArcProgressView.framework in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | B560E6B336A3E32A316E8DFA /* Frameworks */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | ); 70 | name = Frameworks; 71 | sourceTree = ""; 72 | }; 73 | DF444D791AAEFF3900BB2721 = { 74 | isa = PBXGroup; 75 | children = ( 76 | DF444D921AAEFF3900BB2721 /* ESArcProgressViewTests */, 77 | DF444D841AAEFF3900BB2721 /* Products */, 78 | DF7ECB621B0226A200B28386 /* Pods */, 79 | B560E6B336A3E32A316E8DFA /* Frameworks */, 80 | ); 81 | sourceTree = ""; 82 | }; 83 | DF444D841AAEFF3900BB2721 /* Products */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | DF444D831AAEFF3900BB2721 /* ESArcProgressView.framework */, 87 | DF444D8E1AAEFF3900BB2721 /* ESArcProgressViewTests.xctest */, 88 | ); 89 | name = Products; 90 | sourceTree = ""; 91 | }; 92 | DF444D921AAEFF3900BB2721 /* ESArcProgressViewTests */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | DF444D951AAEFF3900BB2721 /* ESArcProgressViewTests.m */, 96 | DF444D931AAEFF3900BB2721 /* Supporting Files */, 97 | ); 98 | path = ESArcProgressViewTests; 99 | sourceTree = ""; 100 | }; 101 | DF444D931AAEFF3900BB2721 /* Supporting Files */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | DF444D941AAEFF3900BB2721 /* Info.plist */, 105 | ); 106 | name = "Supporting Files"; 107 | sourceTree = ""; 108 | }; 109 | DF7ECB621B0226A200B28386 /* Pods */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | DF7ECB631B0226B100B28386 /* Pods.debug.xcconfig */, 113 | DF7ECB641B0226B100B28386 /* Pods.release.xcconfig */, 114 | ); 115 | name = Pods; 116 | sourceTree = ""; 117 | }; 118 | /* End PBXGroup section */ 119 | 120 | /* Begin PBXHeadersBuildPhase section */ 121 | DF444D801AAEFF3900BB2721 /* Headers */ = { 122 | isa = PBXHeadersBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | ); 126 | runOnlyForDeploymentPostprocessing = 0; 127 | }; 128 | /* End PBXHeadersBuildPhase section */ 129 | 130 | /* Begin PBXNativeTarget section */ 131 | DF444D821AAEFF3900BB2721 /* ESArcProgressView */ = { 132 | isa = PBXNativeTarget; 133 | buildConfigurationList = DF444D991AAEFF3900BB2721 /* Build configuration list for PBXNativeTarget "ESArcProgressView" */; 134 | buildPhases = ( 135 | DF444D7E1AAEFF3900BB2721 /* Sources */, 136 | DF444D7F1AAEFF3900BB2721 /* Frameworks */, 137 | DF444D801AAEFF3900BB2721 /* Headers */, 138 | DF444D811AAEFF3900BB2721 /* Resources */, 139 | ); 140 | buildRules = ( 141 | ); 142 | dependencies = ( 143 | ); 144 | name = ESArcProgressView; 145 | productName = ESArcProgressView; 146 | productReference = DF444D831AAEFF3900BB2721 /* ESArcProgressView.framework */; 147 | productType = "com.apple.product-type.framework"; 148 | }; 149 | DF444D8D1AAEFF3900BB2721 /* ESArcProgressViewTests */ = { 150 | isa = PBXNativeTarget; 151 | buildConfigurationList = DF444D9C1AAEFF3900BB2721 /* Build configuration list for PBXNativeTarget "ESArcProgressViewTests" */; 152 | buildPhases = ( 153 | DF444DA71AAF08E000BB2721 /* CopyFiles */, 154 | DF444D8A1AAEFF3900BB2721 /* Sources */, 155 | DF444D8B1AAEFF3900BB2721 /* Frameworks */, 156 | DF444D8C1AAEFF3900BB2721 /* Resources */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | DF444D911AAEFF3900BB2721 /* PBXTargetDependency */, 162 | ); 163 | name = ESArcProgressViewTests; 164 | productName = ESArcProgressViewTests; 165 | productReference = DF444D8E1AAEFF3900BB2721 /* ESArcProgressViewTests.xctest */; 166 | productType = "com.apple.product-type.bundle.unit-test"; 167 | }; 168 | /* End PBXNativeTarget section */ 169 | 170 | /* Begin PBXProject section */ 171 | DF444D7A1AAEFF3900BB2721 /* Project object */ = { 172 | isa = PBXProject; 173 | attributes = { 174 | LastUpgradeCheck = 0620; 175 | ORGANIZATIONNAME = "e-sites"; 176 | TargetAttributes = { 177 | DF444D821AAEFF3900BB2721 = { 178 | CreatedOnToolsVersion = 6.2; 179 | }; 180 | DF444D8D1AAEFF3900BB2721 = { 181 | CreatedOnToolsVersion = 6.2; 182 | }; 183 | }; 184 | }; 185 | buildConfigurationList = DF444D7D1AAEFF3900BB2721 /* Build configuration list for PBXProject "ESArcProgressView" */; 186 | compatibilityVersion = "Xcode 3.2"; 187 | developmentRegion = English; 188 | hasScannedForEncodings = 0; 189 | knownRegions = ( 190 | en, 191 | ); 192 | mainGroup = DF444D791AAEFF3900BB2721; 193 | productRefGroup = DF444D841AAEFF3900BB2721 /* Products */; 194 | projectDirPath = ""; 195 | projectRoot = ""; 196 | targets = ( 197 | DF444D821AAEFF3900BB2721 /* ESArcProgressView */, 198 | DF444D8D1AAEFF3900BB2721 /* ESArcProgressViewTests */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | DF444D811AAEFF3900BB2721 /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | DF444D8C1AAEFF3900BB2721 /* Resources */ = { 212 | isa = PBXResourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | }; 218 | /* End PBXResourcesBuildPhase section */ 219 | 220 | /* Begin PBXSourcesBuildPhase section */ 221 | DF444D7E1AAEFF3900BB2721 /* Sources */ = { 222 | isa = PBXSourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | DF444D8A1AAEFF3900BB2721 /* Sources */ = { 229 | isa = PBXSourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | DF444D961AAEFF3900BB2721 /* ESArcProgressViewTests.m in Sources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | /* End PBXSourcesBuildPhase section */ 237 | 238 | /* Begin PBXTargetDependency section */ 239 | DF444D911AAEFF3900BB2721 /* PBXTargetDependency */ = { 240 | isa = PBXTargetDependency; 241 | target = DF444D821AAEFF3900BB2721 /* ESArcProgressView */; 242 | targetProxy = DF444D901AAEFF3900BB2721 /* PBXContainerItemProxy */; 243 | }; 244 | /* End PBXTargetDependency section */ 245 | 246 | /* Begin XCBuildConfiguration section */ 247 | DF444D971AAEFF3900BB2721 /* Debug */ = { 248 | isa = XCBuildConfiguration; 249 | buildSettings = { 250 | ALWAYS_SEARCH_USER_PATHS = NO; 251 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 252 | CLANG_CXX_LIBRARY = "libc++"; 253 | CLANG_ENABLE_MODULES = YES; 254 | CLANG_ENABLE_OBJC_ARC = YES; 255 | CLANG_WARN_BOOL_CONVERSION = YES; 256 | CLANG_WARN_CONSTANT_CONVERSION = YES; 257 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 258 | CLANG_WARN_EMPTY_BODY = YES; 259 | CLANG_WARN_ENUM_CONVERSION = YES; 260 | CLANG_WARN_INT_CONVERSION = YES; 261 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 265 | COPY_PHASE_STRIP = NO; 266 | CURRENT_PROJECT_VERSION = 1; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | GCC_C_LANGUAGE_STANDARD = gnu99; 269 | GCC_DYNAMIC_NO_PIC = NO; 270 | GCC_OPTIMIZATION_LEVEL = 0; 271 | GCC_PREPROCESSOR_DEFINITIONS = ( 272 | "DEBUG=1", 273 | "$(inherited)", 274 | ); 275 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 276 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 277 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 278 | GCC_WARN_UNDECLARED_SELECTOR = YES; 279 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 280 | GCC_WARN_UNUSED_FUNCTION = YES; 281 | GCC_WARN_UNUSED_VARIABLE = YES; 282 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 283 | MTL_ENABLE_DEBUG_INFO = YES; 284 | ONLY_ACTIVE_ARCH = YES; 285 | SDKROOT = iphoneos; 286 | TARGETED_DEVICE_FAMILY = "1,2"; 287 | VERSIONING_SYSTEM = "apple-generic"; 288 | VERSION_INFO_PREFIX = ""; 289 | }; 290 | name = Debug; 291 | }; 292 | DF444D981AAEFF3900BB2721 /* Release */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ALWAYS_SEARCH_USER_PATHS = NO; 296 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 297 | CLANG_CXX_LIBRARY = "libc++"; 298 | CLANG_ENABLE_MODULES = YES; 299 | CLANG_ENABLE_OBJC_ARC = YES; 300 | CLANG_WARN_BOOL_CONVERSION = YES; 301 | CLANG_WARN_CONSTANT_CONVERSION = YES; 302 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 303 | CLANG_WARN_EMPTY_BODY = YES; 304 | CLANG_WARN_ENUM_CONVERSION = YES; 305 | CLANG_WARN_INT_CONVERSION = YES; 306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 307 | CLANG_WARN_UNREACHABLE_CODE = YES; 308 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 309 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 310 | COPY_PHASE_STRIP = NO; 311 | CURRENT_PROJECT_VERSION = 1; 312 | ENABLE_NS_ASSERTIONS = NO; 313 | ENABLE_STRICT_OBJC_MSGSEND = YES; 314 | GCC_C_LANGUAGE_STANDARD = gnu99; 315 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 316 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 317 | GCC_WARN_UNDECLARED_SELECTOR = YES; 318 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 319 | GCC_WARN_UNUSED_FUNCTION = YES; 320 | GCC_WARN_UNUSED_VARIABLE = YES; 321 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 322 | MTL_ENABLE_DEBUG_INFO = NO; 323 | SDKROOT = iphoneos; 324 | TARGETED_DEVICE_FAMILY = "1,2"; 325 | VALIDATE_PRODUCT = YES; 326 | VERSIONING_SYSTEM = "apple-generic"; 327 | VERSION_INFO_PREFIX = ""; 328 | }; 329 | name = Release; 330 | }; 331 | DF444D9A1AAEFF3900BB2721 /* Debug */ = { 332 | isa = XCBuildConfiguration; 333 | baseConfigurationReference = DF7ECB631B0226B100B28386 /* Pods.debug.xcconfig */; 334 | buildSettings = { 335 | DEFINES_MODULE = YES; 336 | DYLIB_COMPATIBILITY_VERSION = 1; 337 | DYLIB_CURRENT_VERSION = 1; 338 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 339 | INFOPLIST_FILE = ESArcProgressView/Info.plist; 340 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 341 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 342 | PRODUCT_NAME = "$(TARGET_NAME)"; 343 | SKIP_INSTALL = YES; 344 | }; 345 | name = Debug; 346 | }; 347 | DF444D9B1AAEFF3900BB2721 /* Release */ = { 348 | isa = XCBuildConfiguration; 349 | baseConfigurationReference = DF7ECB641B0226B100B28386 /* Pods.release.xcconfig */; 350 | buildSettings = { 351 | DEFINES_MODULE = YES; 352 | DYLIB_COMPATIBILITY_VERSION = 1; 353 | DYLIB_CURRENT_VERSION = 1; 354 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 355 | INFOPLIST_FILE = ESArcProgressView/Info.plist; 356 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 357 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 358 | PRODUCT_NAME = "$(TARGET_NAME)"; 359 | SKIP_INSTALL = YES; 360 | }; 361 | name = Release; 362 | }; 363 | DF444D9D1AAEFF3900BB2721 /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | baseConfigurationReference = DF7ECB631B0226B100B28386 /* Pods.debug.xcconfig */; 366 | buildSettings = { 367 | FRAMEWORK_SEARCH_PATHS = ( 368 | "$(SDKROOT)/Developer/Library/Frameworks", 369 | "$(inherited)", 370 | ); 371 | GCC_PREPROCESSOR_DEFINITIONS = ( 372 | "DEBUG=1", 373 | "$(inherited)", 374 | ); 375 | INFOPLIST_FILE = ESArcProgressViewTests/Info.plist; 376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 377 | PRODUCT_NAME = "$(TARGET_NAME)"; 378 | }; 379 | name = Debug; 380 | }; 381 | DF444D9E1AAEFF3900BB2721 /* Release */ = { 382 | isa = XCBuildConfiguration; 383 | baseConfigurationReference = DF7ECB641B0226B100B28386 /* Pods.release.xcconfig */; 384 | buildSettings = { 385 | FRAMEWORK_SEARCH_PATHS = ( 386 | "$(SDKROOT)/Developer/Library/Frameworks", 387 | "$(inherited)", 388 | ); 389 | INFOPLIST_FILE = ESArcProgressViewTests/Info.plist; 390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 391 | PRODUCT_NAME = "$(TARGET_NAME)"; 392 | }; 393 | name = Release; 394 | }; 395 | /* End XCBuildConfiguration section */ 396 | 397 | /* Begin XCConfigurationList section */ 398 | DF444D7D1AAEFF3900BB2721 /* Build configuration list for PBXProject "ESArcProgressView" */ = { 399 | isa = XCConfigurationList; 400 | buildConfigurations = ( 401 | DF444D971AAEFF3900BB2721 /* Debug */, 402 | DF444D981AAEFF3900BB2721 /* Release */, 403 | ); 404 | defaultConfigurationIsVisible = 0; 405 | defaultConfigurationName = Release; 406 | }; 407 | DF444D991AAEFF3900BB2721 /* Build configuration list for PBXNativeTarget "ESArcProgressView" */ = { 408 | isa = XCConfigurationList; 409 | buildConfigurations = ( 410 | DF444D9A1AAEFF3900BB2721 /* Debug */, 411 | DF444D9B1AAEFF3900BB2721 /* Release */, 412 | ); 413 | defaultConfigurationIsVisible = 0; 414 | defaultConfigurationName = Release; 415 | }; 416 | DF444D9C1AAEFF3900BB2721 /* Build configuration list for PBXNativeTarget "ESArcProgressViewTests" */ = { 417 | isa = XCConfigurationList; 418 | buildConfigurations = ( 419 | DF444D9D1AAEFF3900BB2721 /* Debug */, 420 | DF444D9E1AAEFF3900BB2721 /* Release */, 421 | ); 422 | defaultConfigurationIsVisible = 0; 423 | defaultConfigurationName = Release; 424 | }; 425 | /* End XCConfigurationList section */ 426 | }; 427 | rootObject = DF444D7A1AAEFF3900BB2721 /* Project object */; 428 | } 429 | -------------------------------------------------------------------------------- /ESArcProgressView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ESArcProgressView.xcodeproj/xcshareddata/xcschemes/ESArcProgressView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /ESArcProgressView.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ESArcProgressView/ESArcProgressView+Animations.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESArcProgressView+Animations.h 3 | // CircleDraw 4 | // 5 | // Created by Bas van Kuijck on 11-03-15. 6 | // Copyright (c) 2015 e-sites. All rights reserved. 7 | // 8 | 9 | #import "ESArcProgressViewCore.h" 10 | #include "easing.h" 11 | 12 | typedef void (^ESArcProgressViewUpdateBlock)(CGFloat animationProgress); 13 | 14 | @interface ESArcProgressView (Animations) 15 | 16 | 17 | /** 18 | * @author Bas van Kuijck 19 | * 20 | * Animate to a given value with a duration of 1.0seconds and linear easing 21 | * 22 | * @param toValue CGFloat (somewhere between 0.0 and 1.0f) 23 | * 24 | * @since 1.5 25 | * @date 10/03/2015 26 | */ 27 | - (void)animateTo:(CGFloat)toValue; 28 | 29 | /** 30 | * @author Bas van Kuijck 31 | * 32 | * Animate to a given value with a given duration and a linear easing 33 | * 34 | * @param toValue CGFloat (somewhere between 0.0 and 1.0f) 35 | * @param duration NSTimeInterval Duration 36 | * 37 | * @since 1.5 38 | * @date 10/03/2015 39 | */ 40 | - (void)animateTo:(CGFloat)toValue withDuration:(NSTimeInterval)duration; 41 | 42 | /** 43 | * @author Bas van Kuijck 44 | * 45 | * Animate to a given value with a duration and custom easing 46 | * @see https://github.com/warrenm/AHEasing for possible easingFunction values 47 | * 48 | * @param toValue CGFloat 49 | * @param duration NSTimeInterval 50 | * @param easingFunction AHEasingFunction 51 | * 52 | * @since 1.5 53 | * @date 10/03/2015 54 | */ 55 | - (void)animateTo:(CGFloat)toValue withDuration:(NSTimeInterval)duration withEasingFunction:(AHEasingFunction)easingFunction; 56 | 57 | /** 58 | * @author Bas van Kuijck 59 | * 60 | * Animate to a given value with a duration and custom easing 61 | * Every time a new progress is done the updateHandler will be called 62 | * @see https://github.com/warrenm/AHEasing for possible easingFunction values 63 | * 64 | * @param toValue CGFloat 65 | * @param duration NSTimeInterval 66 | * @param easingFunction AHEasingFunction 67 | * @param updateHandler ESArcProgressViewUpdateBlock 68 | * 69 | * @since 1.5 70 | * @date 10/03/2015 71 | */ 72 | - (void)animateTo:(CGFloat)toValue withDuration:(NSTimeInterval)duration withEasingFunction:(AHEasingFunction)easingFunction withUpdateHandler:(ESArcProgressViewUpdateBlock)updateHandler; 73 | 74 | /** 75 | * @author Bas van Kuijck 76 | * 77 | * Stops an active animation 78 | * 79 | * @since 1.5 80 | * @date 10/03/2015 81 | */ 82 | - (void)stopAnimation; 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /ESArcProgressView/ESArcProgressView+Animations.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESArcProgressView+Animations.m 3 | // CircleDraw 4 | // 5 | // Created by Bas van Kuijck on 11-03-15. 6 | // Copyright (c) 2015 e-sites. All rights reserved. 7 | // 8 | 9 | #import "ESArcProgressView+Animations.h" 10 | #import 11 | 12 | static char kEasingFunctionKey; 13 | static char kAnimationTimerKey; 14 | static char kAnimationStepKey; 15 | static char kUpdateHandlerKey; 16 | 17 | @implementation ESArcProgressView (Animations) 18 | 19 | #pragma mark - Animation 20 | // ____________________________________________________________________________________________________________________ 21 | 22 | - (void)animateTo:(CGFloat)toValue 23 | { 24 | [self animateTo:toValue withDuration:1]; 25 | } 26 | 27 | #define kFPS 60.0f 28 | 29 | - (void)animateTo:(CGFloat)toValue withDuration:(NSTimeInterval)duration 30 | { 31 | [self animateTo:toValue withDuration:1.0f withEasingFunction:LinearInterpolation]; 32 | } 33 | 34 | - (void)animateTo:(CGFloat)toValue withDuration:(NSTimeInterval)duration withEasingFunction:(AHEasingFunction)easingFunction 35 | { 36 | [self animateTo:toValue withDuration:duration withEasingFunction:easingFunction withUpdateHandler:nil]; 37 | } 38 | 39 | - (void)animateTo:(CGFloat)toValue withDuration:(NSTimeInterval)duration withEasingFunction:(AHEasingFunction)easingFunction withUpdateHandler:(ESArcProgressViewUpdateBlock)updateHandler 40 | { 41 | if (duration == 0) { 42 | [self setProgress:toValue]; 43 | return; 44 | } 45 | 46 | objc_setAssociatedObject(self, &kUpdateHandlerKey, updateHandler, OBJC_ASSOCIATION_COPY_NONATOMIC); 47 | NSValue *nsvalue = [NSValue valueWithBytes:&easingFunction objCType:@encode(AHEasingFunction)]; 48 | objc_setAssociatedObject(self, &kEasingFunctionKey, nsvalue, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 49 | NSTimer *timer = objc_getAssociatedObject(self, &kAnimationTimerKey); 50 | [timer invalidate]; 51 | toValue = fminf(fmaxf(0.0f, toValue), 1.0f); 52 | 53 | objc_setAssociatedObject(self, &kAnimationStepKey, @(0), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 54 | timer = [NSTimer scheduledTimerWithTimeInterval:1.0f / kFPS target:self selector:@selector(_animationTick:) userInfo:@{ 55 | @"from": @(self.progress), 56 | @"to": @(toValue), 57 | @"duration": @(duration) 58 | } repeats:YES]; 59 | objc_setAssociatedObject(self, &kAnimationTimerKey, timer, OBJC_ASSOCIATION_RETAIN); 60 | } 61 | 62 | - (void)_animationTick:(NSTimer *)timer 63 | { 64 | CGFloat fromValue = [timer.userInfo[@"from"] floatValue]; 65 | CGFloat toValue = [timer.userInfo[@"to"] floatValue]; 66 | NSTimeInterval duration = [timer.userInfo[@"duration"] doubleValue]; 67 | 68 | CGFloat percPercStep = (toValue >= fromValue ? (toValue - fromValue) : (fromValue - toValue))/(duration * kFPS); 69 | NSInteger animationStep = [objc_getAssociatedObject(self, &kAnimationStepKey) integerValue]; 70 | animationStep++; 71 | objc_setAssociatedObject(self, &kAnimationStepKey, @(animationStep), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 72 | 73 | ESArcProgressViewUpdateBlock updateBlock = objc_getAssociatedObject(self, &kUpdateHandlerKey); 74 | 75 | CGFloat animationPercentage = animationStep * percPercStep; 76 | if (animationPercentage >= 1.0f) { 77 | ESArcProgressViewUpdateBlock handler = updateBlock; 78 | [self stopAnimation]; 79 | if (handler != nil) { 80 | handler(animationPercentage); 81 | handler = nil; 82 | } 83 | return; 84 | } 85 | NSValue *value = objc_getAssociatedObject(self, &kEasingFunctionKey); 86 | CGFloat p = animationPercentage; 87 | if (value != nil) { 88 | AHEasingFunction function; 89 | [value getValue:&function]; 90 | p = function(animationPercentage); 91 | } 92 | 93 | self.progress = fromValue + ((toValue - fromValue) * p); 94 | 95 | if (updateBlock != nil) { 96 | updateBlock(animationPercentage); 97 | } 98 | } 99 | 100 | - (void)stopAnimation 101 | { 102 | objc_setAssociatedObject(self, &kEasingFunctionKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 103 | objc_setAssociatedObject(self, &kAnimationStepKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 104 | objc_setAssociatedObject(self, &kUpdateHandlerKey, nil, OBJC_ASSOCIATION_COPY_NONATOMIC); 105 | NSTimer *timer = objc_getAssociatedObject(self, &kAnimationTimerKey); 106 | if (timer != nil) { 107 | self.progress = [timer.userInfo[@"to"] floatValue]; 108 | } 109 | objc_setAssociatedObject(self, &kAnimationTimerKey, nil, OBJC_ASSOCIATION_RETAIN); 110 | [timer invalidate]; 111 | } 112 | 113 | #pragma mark - Destructor 114 | // ____________________________________________________________________________________________________________________ 115 | 116 | - (void)dealloc 117 | { 118 | [self stopAnimation]; 119 | } 120 | 121 | @end -------------------------------------------------------------------------------- /ESArcProgressView/ESArcProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESArcProgressView.h 3 | // CircleDraw 4 | // 5 | // Created by Bas van Kuijck on 11-03-15. 6 | // Copyright (c) 2015 e-sites. All rights reserved. 7 | // 8 | 9 | #ifndef _ESArcProgressView_h 10 | #define _ESArcProgressView_h 11 | 12 | #import "ESArcProgressViewCore.h" 13 | #import "ESArcProgressView+Animations.h" 14 | #import "ESMultipleArcProgressView.h" 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /ESArcProgressView/ESArcProgressViewCore.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESArcProgressViewCore.h 3 | // iOS.Library 4 | // 5 | // Created by Bas van Kuijck on 04-03-15. 6 | // Copyright (c) 2015 e-sites. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSInteger, ESArcProgressCenterDotStyle) { 12 | ESArcProgressCenterDotStyleNone = 0, 13 | ESArcProgressCenterDotStyleBegin, 14 | ESArcProgressCenterDotStyleEnd, 15 | ESArcProgressCenterDotStyleBeginAndEnd 16 | }; 17 | 18 | @interface ESArcProgressView : UIView 19 | 20 | /** 21 | * @author Bas van Kuijck 22 | * 23 | * The color of the progress 24 | * @note Default = Green 25 | * 26 | * @since 1.0 27 | * @date 04/03/2015 28 | */ 29 | @property (nonatomic, strong) UIColor *color; 30 | 31 | /** 32 | * @author Bas van Kuijck 33 | * 34 | * The color of the center dots at the beginning and end of the progress vew 35 | * @note Default = white 36 | * 37 | * @since 1.0 38 | * @date 04/03/2015 39 | */ 40 | @property (nonatomic, strong) UIColor *dotColor; 41 | 42 | /** 43 | * @author Bas van Kuijck 44 | * 45 | * The procentual progress of this view 46 | * @note Default = 0 47 | * @warning This must be a value somewheren between 0.0 and 1.0 48 | * 49 | * @since 1.0 50 | * @date 04/03/2015 51 | */ 52 | @property (nonatomic, readwrite) CGFloat progress; 53 | 54 | /** 55 | * @author Bas van Kuijck 56 | * 57 | * The lineWidth of the progress (aka the diameter) 58 | * @note Default = 20 pixels 59 | * 60 | * @since 1.0 61 | * @date 04/03/2015 62 | */ 63 | @property (nonatomic, readwrite) CGFloat lineWidth; 64 | 65 | /** 66 | * @author Bas van Kuijck 67 | * 68 | * Should the progress have a drop shadow 69 | * @note Default = YES 70 | * 71 | * @since 1.0 72 | * @date 04/03/2015 73 | */ 74 | @property (nonatomic, readwrite, getter=shouldShowShadow) BOOL showShadow; 75 | 76 | /** 77 | * @author Bas van Kuijck 78 | * 79 | * The label to show in the progress view 80 | * @note Default = nil 81 | * 82 | * @since 1.2 83 | * @date 06/03/2015 84 | */ 85 | @property (nonatomic, copy) NSString *text; 86 | 87 | /** 88 | * @author Bas van Kuijck 89 | * 90 | * Should a small line fragment be visible when the progress is 0.0 91 | * @note Default: NO 92 | * 93 | * @since 1.3 94 | * @date 06/03/2015 95 | */ 96 | @property (nonatomic, readwrite, getter=shouldShowZeroProgress) BOOL showZeroProgress; 97 | 98 | /** 99 | * @author Bas van Kuijck 100 | * 101 | * Should the progress view show a small center dot 102 | * @deprecated Use [ESArcProgressView centerDotStyle] instead 103 | * @note Default = YES 104 | * 105 | * @since 1.0 106 | * @date 04/03/2015 107 | */ 108 | @property (nonatomic, readwrite, getter=shouldShowCenterDot) BOOL showCenterDot __attribute__((deprecated("use centerDotStyle instead"))); 109 | 110 | /** 111 | * @author Bas van Kuijck 112 | * 113 | * What center dot style should be used 114 | * @note Default = ESArcProgressCenterDotStyleBeginAndEnd 115 | * 116 | * @since 1.1 117 | * @date 05/03/2015 118 | */ 119 | @property (nonatomic, readwrite) ESArcProgressCenterDotStyle centerDotStyle; 120 | 121 | 122 | /** 123 | * @author Bas van Kuijck 124 | * 125 | * The image to show as a center dot in the arc line 126 | * @note Default = nil 127 | * 128 | * @date 10/03/2015 129 | * @since 1.4 130 | */ 131 | @property (nonatomic, strong) UIImage *centerDotImage; 132 | 133 | /** 134 | * @author Bas van Kuijck 135 | * 136 | * Should the `centerDotImage` be colorized according to the `dotColor` ? 137 | * @note Default = YES 138 | * 139 | * @since 1.4 140 | * @date 10/03/2015 141 | */ 142 | @property (nonatomic, readwrite, getter=shouldColorizeCenterDotImage) BOOL colorizeCenterDotImage; 143 | 144 | 145 | @end 146 | 147 | @interface UIView (ESMultipleArcProgressViewGenerateUIImage) 148 | - (UIImage *)generateImage __attribute__((deprecated("use es_imageOfView instead"))); 149 | - (UIImage *)es_imageOfView; 150 | - (UIImage *)es_imageOfViewWithScale:(CGFloat)scale; 151 | @end -------------------------------------------------------------------------------- /ESArcProgressView/ESArcProgressViewCore.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESArcProgressViewCore.m 3 | // CircleDraw 4 | // 5 | // Created by Bas van Kuijck on 04-03-15. 6 | // Copyright (c) 2015 e-sites. All rights reserved. 7 | // 8 | 9 | #import "ESArcProgressViewCore.h" 10 | 11 | 12 | @implementation ESArcProgressView { 13 | UIColor *_customBackgroundColor; 14 | } 15 | @synthesize color=_color,showShadow=_showShadow,showCenterDot,progress=_percentage,lineWidth=_lineWidth,dotColor=_dotColor,centerDotStyle=_centerDotStyle,text=_text,showZeroProgress=_showZeroProgress,centerDotImage=_centerDotImage,colorizeCenterDotImage=_colorizeCenterDotImage; 16 | 17 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 18 | { 19 | if (self = [super initWithCoder:aDecoder]) { 20 | [self _init]; 21 | } 22 | return self; 23 | } 24 | 25 | - (instancetype)init 26 | { 27 | if (self = [super init]) { 28 | [self _init]; 29 | } 30 | return self; 31 | } 32 | 33 | - (instancetype)initWithFrame:(CGRect)frame 34 | { 35 | if (self = [super initWithFrame:frame]) { 36 | [self _init]; 37 | } 38 | return self; 39 | } 40 | 41 | - (void)_init 42 | { 43 | [self setOpaque:NO]; 44 | _showShadow = YES; 45 | _colorizeCenterDotImage = YES; 46 | _centerDotStyle = ESArcProgressCenterDotStyleBeginAndEnd; 47 | _lineWidth = 20; 48 | _color = [UIColor greenColor]; 49 | _dotColor = [UIColor whiteColor]; 50 | } 51 | 52 | - (void)layoutSubviews 53 | { 54 | [self setOpaque:NO]; 55 | [super setBackgroundColor:[UIColor clearColor]]; 56 | } 57 | 58 | #pragma mark - Properties 59 | // ____________________________________________________________________________________________________________________ 60 | 61 | - (void)setColor:(UIColor *)aColor 62 | { 63 | _color = aColor; 64 | [self setNeedsDisplay]; 65 | } 66 | 67 | - (void)setBackgroundColor:(UIColor *)aBackgroundColor 68 | { 69 | _customBackgroundColor = aBackgroundColor; 70 | [self setNeedsDisplay]; 71 | } 72 | 73 | - (void)setShowShadow:(BOOL)aShowShadow 74 | { 75 | _showShadow = aShowShadow; 76 | [self setNeedsDisplay]; 77 | } 78 | 79 | - (void)setProgress:(CGFloat)aProgress 80 | { 81 | _percentage = fminf(1.0f, fmaxf(0.0f, aProgress)); 82 | [self setNeedsDisplay]; 83 | } 84 | 85 | - (void)setLineWidth:(CGFloat)aLineWidth 86 | { 87 | _lineWidth = fmaxf(1, aLineWidth); 88 | [self setNeedsDisplay]; 89 | } 90 | 91 | - (void)setCenterDotStyle:(ESArcProgressCenterDotStyle)aCenterDotStyle 92 | { 93 | _centerDotStyle = aCenterDotStyle; 94 | [self setNeedsDisplay]; 95 | } 96 | 97 | - (void)setDotColor:(UIColor *)aDotColor 98 | { 99 | _dotColor = aDotColor; 100 | [self setNeedsDisplay]; 101 | } 102 | 103 | - (void)setText:(NSString *)aText 104 | { 105 | _text = [aText copy]; 106 | [self setNeedsDisplay]; 107 | } 108 | 109 | - (void)setShowZeroProgress:(BOOL)aShowZeroProgress 110 | { 111 | _showZeroProgress = aShowZeroProgress; 112 | [self setNeedsDisplay]; 113 | } 114 | 115 | - (void)setCenterDotImage:(UIImage *)centerDotImage 116 | { 117 | _centerDotImage = centerDotImage; 118 | [self setNeedsDisplay]; 119 | } 120 | 121 | - (void)setColorizeCenterDotImage:(BOOL)colorizeCenterDotImage 122 | { 123 | _colorizeCenterDotImage = colorizeCenterDotImage; 124 | [self setNeedsDisplay]; 125 | } 126 | 127 | #pragma mark - Drawing 128 | // ____________________________________________________________________________________________________________________ 129 | 130 | - (void)drawRect:(CGRect)rect 131 | { 132 | // ------------------------------------------------ 133 | // Configuration values 134 | 135 | const CGFloat perc = fmaxf(self.shouldShowZeroProgress ? 0.000001 : 0, self.progress); 136 | const CGFloat lineRadius = self.lineWidth / 2; 137 | const CGFloat midDotRadius = fmaxf(1.0f, lineRadius * 0.3); 138 | 139 | // ------------------------------------------------ 140 | 141 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 142 | CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2); 143 | CGFloat delta = (360 * perc) * M_PI / 180; 144 | CGFloat innerRadius = fminf(center.x, center.y) - lineRadius; 145 | 146 | CGContextSetLineCap(ctx, kCGLineCapRound); 147 | CGContextSetLineWidth(ctx, lineRadius * 2); 148 | 149 | // Draw background 150 | UIColor *bgColor = _customBackgroundColor; 151 | if (bgColor == nil) { 152 | bgColor = [self.color colorWithAlphaComponent:.5]; 153 | } 154 | CGContextSetStrokeColorWithColor(ctx, bgColor.CGColor); 155 | CGMutablePathRef path = CGPathCreateMutable(); 156 | CGPathAddRelativeArc(path, NULL, center.x, center.y, innerRadius, -(M_PI / 2), M_PI * 2); 157 | CGContextAddPath(ctx, path); 158 | CGContextStrokePath(ctx); 159 | CGPathRelease(path); 160 | if (perc > 0) { 161 | 162 | CGContextSaveGState(ctx); 163 | // Draw mask 164 | path = CGPathCreateMutable(); 165 | CGPathAddEllipseInRect(path, nil, rect); 166 | CGPathAddEllipseInRect(path, nil, CGRectMake(lineRadius * 2, lineRadius * 2, (innerRadius - lineRadius) * 2, (innerRadius - lineRadius) * 2)); 167 | CGContextAddPath(ctx, path); 168 | CGContextClosePath(ctx); 169 | CGContextEOClip(ctx); 170 | CGPathRelease(path); 171 | 172 | // Shadow 173 | if (self.shouldShowShadow) { 174 | CGContextSetShadowWithColor(ctx, CGSizeZero, lineRadius * 1.5f, [UIColor colorWithWhite:0 alpha:.75].CGColor); 175 | } 176 | 177 | // Draw foreground 178 | path = CGPathCreateMutable(); 179 | CGContextSetStrokeColorWithColor(ctx, self.color.CGColor); 180 | CGPathAddRelativeArc(path, NULL, center.x, center.y, innerRadius, -(M_PI / 2), delta); 181 | CGContextAddPath(ctx, path); 182 | CGContextStrokePath(ctx); 183 | CGContextRestoreGState(ctx); 184 | CGPathRelease(path); 185 | } 186 | 187 | 188 | if (self.text.length > 0) { 189 | NSMutableAttributedString *attstr = [[NSMutableAttributedString alloc] initWithString:self.text]; 190 | [attstr beginEditing]; 191 | NSShadow *shadow = [[NSShadow alloc] init]; 192 | [shadow setShadowBlurRadius:0]; 193 | [shadow setShadowColor:[UIColor blackColor]]; 194 | [shadow setShadowOffset:CGSizeMake(1, 1)]; 195 | 196 | NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init]; 197 | [paragraph setAlignment:NSTextAlignmentRight]; 198 | [attstr addAttributes:@{ 199 | NSFontAttributeName: [UIFont boldSystemFontOfSize:self.lineWidth / 1.2f], 200 | NSShadowAttributeName: shadow, 201 | NSParagraphStyleAttributeName: paragraph, 202 | NSForegroundColorAttributeName: self.color 203 | } range:NSMakeRange(0, self.text.length)]; 204 | [attstr endEditing]; 205 | [attstr drawInRect:CGRectMake(0, 0, center.x - 15, self.lineWidth)]; 206 | } 207 | 208 | // Draw white begin / end dots 209 | if (self.centerDotStyle == ESArcProgressCenterDotStyleNone) { 210 | return; 211 | } 212 | 213 | UIImage *_image = [self _centerDotColorizedImage]; 214 | CGSize imageSize = _image.size; 215 | if (self.centerDotImage == nil) { 216 | CGContextSetFillColorWithColor(ctx, self.dotColor.CGColor); 217 | } else { 218 | imageSize.height = fminf(imageSize.height, (lineRadius * 2) * 0.7); 219 | imageSize.width = fminf(imageSize.width, (lineRadius * 2) * 0.7); 220 | } 221 | 222 | if ((self.centerDotStyle == ESArcProgressCenterDotStyleBeginAndEnd || self.centerDotStyle == ESArcProgressCenterDotStyleBegin) && perc > 0) { 223 | if (_image != nil) { 224 | [_image drawInRect:CGRectMake(center.x - imageSize.width / 2, lineRadius - imageSize.height / 2, imageSize.width, imageSize.height)]; 225 | } else { 226 | CGContextAddEllipseInRect(ctx, CGRectMake(center.x - midDotRadius, center.y - innerRadius - midDotRadius, midDotRadius * 2, midDotRadius * 2)); 227 | } 228 | } 229 | 230 | if (((self.centerDotStyle == ESArcProgressCenterDotStyleBeginAndEnd && self.progress < 1.0f) || self.centerDotStyle == ESArcProgressCenterDotStyleEnd) && self.progress > 0) { 231 | CGFloat w = sinf(delta) * innerRadius; 232 | CGFloat h = cosf(delta) * innerRadius; 233 | CGFloat x = center.x + w; 234 | CGFloat y = center.y - h; 235 | 236 | if (_image != nil) { 237 | [_image drawInRect:CGRectMake(x - imageSize.width / 2, y - imageSize.height / 2, imageSize.width, imageSize.height)]; 238 | } else { 239 | CGContextAddEllipseInRect(ctx, CGRectMake(x - midDotRadius, y - midDotRadius, midDotRadius * 2, midDotRadius * 2)); 240 | 241 | } 242 | } 243 | 244 | if (self.centerDotImage == nil) { 245 | CGContextSetShadowWithColor(ctx, CGSizeZero, 0, nil); 246 | CGContextSetLineWidth(ctx, 0); 247 | CGContextFillPath(ctx); 248 | } 249 | } 250 | 251 | /** 252 | * @author Bas van Kuijck 253 | * 254 | * Creates a colorized UIImage 255 | * Credits to https://github.com/raymondjavaxx/UIImage-RTTint 256 | * 257 | * @return UIImage 258 | * 259 | * @since 1.3 260 | * @date 10/03/2015 261 | */ 262 | - (UIImage *)_centerDotColorizedImage 263 | { 264 | if (self.centerDotImage == nil || !self.colorizeCenterDotImage) { 265 | return self.centerDotImage; 266 | } 267 | CGRect imageRect = CGRectMake(0.0f, 0.0f, self.centerDotImage.size.width, self.centerDotImage.size.height); 268 | 269 | UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, self.centerDotImage.scale); 270 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 271 | 272 | [self.centerDotImage drawInRect:imageRect]; 273 | 274 | CGContextSetFillColorWithColor(ctx, [self.dotColor CGColor]); 275 | CGContextSetAlpha(ctx, 1.0f); 276 | CGContextSetBlendMode(ctx, kCGBlendModeSourceAtop); 277 | CGContextFillRect(ctx, imageRect); 278 | 279 | CGImageRef imageRef = CGBitmapContextCreateImage(ctx); 280 | UIImage *darkImage = [UIImage imageWithCGImage:imageRef 281 | scale:self.centerDotImage.scale 282 | orientation:self.centerDotImage.imageOrientation]; 283 | CGImageRelease(imageRef); 284 | 285 | UIGraphicsEndImageContext(); 286 | 287 | return darkImage; 288 | } 289 | 290 | @end 291 | 292 | @implementation UIView (ESMultipleArcProgressViewGenerateUIImage) 293 | 294 | - (UIImage *)generateImage 295 | { 296 | NSAssert(NO, @"use es_imageOfView instead"); 297 | return nil; 298 | } 299 | 300 | - (UIImage *)es_imageOfView 301 | { 302 | return [self es_imageOfViewWithScale:0]; 303 | } 304 | 305 | - (UIImage *)es_imageOfViewWithScale:(CGFloat)scale 306 | { 307 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, scale); 308 | [self.layer renderInContext:UIGraphicsGetCurrentContext()]; 309 | UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); 310 | UIGraphicsEndImageContext(); 311 | return img; 312 | } 313 | 314 | @end -------------------------------------------------------------------------------- /ESArcProgressView/ESMultipleArcProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ESMultipleArcProgressView.h 3 | // CircleDraw 4 | // 5 | // Created by Bas van Kuijck on 04-03-15. 6 | // Copyright (c) 2015 e-sites. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ESArcProgressViewCore.h" 11 | 12 | @interface ESMultipleArcProgressView : UIView 13 | 14 | /** 15 | * @author Bas van Kuijck 16 | * 17 | * How much margin should be used betwene individual `ESArcProgressView` 18 | * @note Default = 1 19 | * 20 | * @since 1.0 21 | * @date 04/03/2015 22 | */ 23 | @property (nonatomic, readwrite) CGFloat margin; 24 | 25 | /** 26 | * @author Bas van Kuijck 27 | * 28 | * Add an `ESArcProgressView` to the view stack 29 | * @see ESArcProgressView 30 | * 31 | * @param progressView ESArcProgressView 32 | * 33 | * @since 1.0 34 | * @date 04/03/2015 35 | */ 36 | - (void)addArcProgressView:(ESArcProgressView *)progressView; 37 | 38 | /** 39 | * @author Bas van Kuijck 40 | * 41 | * Remove a specific `ESArcProgressView` fromthe view stack 42 | * @see ESArcProgressView 43 | * 44 | * @param progressView ESArcProgressView 45 | * 46 | * @since 1.0 47 | * @date 04/03/2015 48 | */ 49 | - (void)removeArcProgressView:(ESArcProgressView *)progressView; 50 | 51 | - (void)addSubview:(UIView *)view __attribute__((unavailable("use addArcProgressView: instead"))); 52 | - (void)insertSubview:(UIView *)view atIndex:(NSInteger)index __attribute__((unavailable("use addArcProgressView: instead"))); 53 | - (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview __attribute__((unavailable("use addArcProgressView: instead"))); 54 | - (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview __attribute__((unavailable("use addArcProgressView: instead"))); 55 | 56 | @end 57 | 58 | @interface ESArcProgressView (Multiple) 59 | 60 | /** 61 | * @author Bas van Kuijck 62 | * 63 | * A property that points the a `ESMultipleArcProgressView` if used. 64 | * @warning: Do not call this property yourself, `ESMultipleArcProgressView` will do that for you 65 | * @see ESMultipleArcProgressView for more information 66 | * 67 | * @since 1.0 68 | * @date 04/03/2015 69 | */ 70 | 71 | @property (nonatomic, weak) ESMultipleArcProgressView *multipleArcProgressView; 72 | 73 | @end -------------------------------------------------------------------------------- /ESArcProgressView/ESMultipleArcProgressView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESMultipleArcProgressView.m 3 | // CircleDraw 4 | // 5 | // Created by Bas van Kuijck on 04-03-15. 6 | // Copyright (c) 2015 e-sites. All rights reserved. 7 | // 8 | 9 | #import "ESMultipleArcProgressView.h" 10 | #import 11 | 12 | @implementation ESMultipleArcProgressView { 13 | ESArcProgressView *_previousArcProgressView; 14 | } 15 | @synthesize margin=_margin; 16 | 17 | #pragma mark - Constructor 18 | // ____________________________________________________________________________________________________________________ 19 | 20 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 21 | { 22 | if (self = [super initWithCoder:aDecoder]) { 23 | [self _init]; 24 | } 25 | return self; 26 | } 27 | 28 | - (instancetype)init 29 | { 30 | if (self = [super init]) { 31 | [self _init]; 32 | } 33 | return self; 34 | } 35 | 36 | - (instancetype)initWithFrame:(CGRect)frame 37 | { 38 | if (self = [super initWithFrame:frame]) { 39 | [self _init]; 40 | } 41 | return self; 42 | } 43 | 44 | - (void)_init 45 | { 46 | [self setOpaque:NO]; 47 | _margin = 1; 48 | } 49 | 50 | #pragma mark - Layout 51 | // ____________________________________________________________________________________________________________________ 52 | 53 | - (void)layoutSubviews 54 | { 55 | [super layoutSubviews]; 56 | [self _updateProgressViews]; 57 | } 58 | 59 | #pragma mark - Adding progress views 60 | // ____________________________________________________________________________________________________________________ 61 | 62 | - (void)addArcProgressView:(ESArcProgressView *)progressView 63 | { 64 | NSAssert([progressView isKindOfClass:[ESArcProgressView class]], @"view <%@:%p> is not type of class ESArcProgressView", NSStringFromClass(progressView.class), progressView); 65 | CGFloat diameterLeft = self.frame.size.width / 2; 66 | if (_previousArcProgressView != nil) { 67 | diameterLeft = _previousArcProgressView.frame.size.width - (_previousArcProgressView.lineWidth * 2); 68 | diameterLeft -= self.margin * 2; 69 | } 70 | NSAssert(diameterLeft >= progressView.lineWidth * 2, @"There is not enough room to place the <%@:%p> with lineWidth %.2f, maximum lineWidth: %.2f", NSStringFromClass(progressView.class), progressView, progressView.lineWidth, diameterLeft / 2); 71 | 72 | [self _placeProgressView:progressView]; 73 | [progressView setMultipleArcProgressView:self]; 74 | [super addSubview:progressView]; 75 | _previousArcProgressView = progressView; 76 | } 77 | 78 | - (void)setMargin:(CGFloat)aMargin 79 | { 80 | _margin = aMargin; 81 | [self _updateProgressViews]; 82 | } 83 | 84 | - (void)_placeProgressView:(ESArcProgressView *)progressView 85 | { 86 | CGRect rect = self.bounds; 87 | if (_previousArcProgressView != nil) { 88 | rect = _previousArcProgressView.frame; 89 | rect.size.width -= (_previousArcProgressView.lineWidth * 2) + (self.margin * 2); 90 | rect.size.height -= (_previousArcProgressView.lineWidth * 2) + (self.margin * 2); 91 | rect.origin.x += _previousArcProgressView.lineWidth + self.margin; 92 | rect.origin.y += _previousArcProgressView.lineWidth + self.margin; 93 | } 94 | 95 | [progressView setFrame:rect]; 96 | [progressView setNeedsDisplay]; 97 | } 98 | 99 | - (void)removeArcProgressView:(ESArcProgressView *)progressView 100 | { 101 | [progressView setMultipleArcProgressView:nil]; 102 | [progressView removeFromSuperview]; 103 | } 104 | 105 | - (void)_updateProgressViews 106 | { 107 | _previousArcProgressView = nil; 108 | NSArray *progressViews = self.subviews; 109 | for (UIView *v in progressViews) { 110 | ESArcProgressView *pv = (ESArcProgressView *)v; 111 | [self _placeProgressView:pv]; 112 | [self bringSubviewToFront:pv]; 113 | _previousArcProgressView = pv; 114 | } 115 | } 116 | 117 | #pragma mark - Overriding 118 | // ____________________________________________________________________________________________________________________ 119 | 120 | - (void)addSubview:(UIView *)view 121 | { 122 | NSAssert(NO, @"%s should not be called", __PRETTY_FUNCTION__); 123 | } 124 | 125 | - (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview 126 | { 127 | NSAssert(NO, @"%s should not be called", __PRETTY_FUNCTION__); 128 | } 129 | 130 | - (void)insertSubview:(UIView *)view atIndex:(NSInteger)index 131 | { 132 | NSAssert(NO, @"%s should not be called", __PRETTY_FUNCTION__); 133 | } 134 | 135 | - (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview 136 | { 137 | NSAssert(NO, @"%s should not be called", __PRETTY_FUNCTION__); 138 | } 139 | 140 | 141 | #pragma mark - Destructor 142 | // ____________________________________________________________________________________________________________________ 143 | 144 | - (void)dealloc 145 | { 146 | _previousArcProgressView = nil; 147 | } 148 | 149 | @end 150 | 151 | @implementation ESArcProgressView (Multiple) 152 | @dynamic multipleArcProgressView; 153 | 154 | static char kMultipleArcProgressViewKey; 155 | 156 | #pragma mark - Method swizzling 157 | // ____________________________________________________________________________________________________________________ 158 | 159 | + (void)load 160 | { 161 | static dispatch_once_t onceToken; 162 | dispatch_once(&onceToken, ^{ 163 | Class class = [self class]; 164 | 165 | SEL originalSelector = @selector(removeFromSuperview); 166 | SEL swizzledSelector = @selector(esarc_removeFromSuperview); 167 | 168 | Method originalMethod = class_getInstanceMethod(class, originalSelector); 169 | Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); 170 | 171 | BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); 172 | 173 | if (didAddMethod) { 174 | class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); 175 | } else { 176 | method_exchangeImplementations(originalMethod, swizzledMethod); 177 | } 178 | }); 179 | } 180 | 181 | #pragma mark - UIView 182 | // ____________________________________________________________________________________________________________________ 183 | 184 | - (void)setMultipleArcProgressView:(ESMultipleArcProgressView *)multipleArcProgressView 185 | { 186 | objc_setAssociatedObject(self, &kMultipleArcProgressViewKey, multipleArcProgressView, OBJC_ASSOCIATION_ASSIGN); 187 | } 188 | 189 | - (ESMultipleArcProgressView *)multipleArcProgressView 190 | { 191 | return objc_getAssociatedObject(self, &kMultipleArcProgressViewKey); 192 | } 193 | 194 | - (void)esarc_removeFromSuperview 195 | { 196 | SEL sel = NSSelectorFromString(@"stopAnimating"); 197 | if ([self respondsToSelector:sel]) { 198 | #pragma clang diagnostic push 199 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 200 | [self performSelector:sel]; 201 | #pragma clang diagnostic pop 202 | } 203 | 204 | if (self.multipleArcProgressView == nil) { 205 | [self esarc_removeFromSuperview]; 206 | } else { 207 | [self.multipleArcProgressView removeArcProgressView:self]; 208 | } 209 | } 210 | 211 | 212 | #pragma mark - Destructor 213 | // ____________________________________________________________________________________________________________________ 214 | 215 | - (void)dealloc 216 | { 217 | self.multipleArcProgressView = nil; 218 | } 219 | 220 | @end -------------------------------------------------------------------------------- /ESArcProgressView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.esites.library.esarcprogressview 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ESArcProgressViewTests/ESArcProgressViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ESArcProgressViewTests.m 3 | // ESArcProgressViewTests 4 | // 5 | // Created by Bas van Kuijck on 10-03-15. 6 | // Copyright (c) 2015 e-sites. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface ESArcProgressViewTests : XCTestCase 14 | 15 | @end 16 | 17 | @implementation ESArcProgressViewTests 18 | 19 | - (void)setUp { 20 | [super setUp]; 21 | } 22 | 23 | - (void)tearDown { 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testImageGeneration 28 | { 29 | CGFloat wh = 200; 30 | ESArcProgressView *pv = [[ESArcProgressView alloc] initWithFrame:CGRectMake(0, 0, wh, wh)]; 31 | [pv setProgress:0.5]; 32 | UIImage *image = [pv es_imageOfView]; 33 | XCTAssert(image.size.width == wh && image.size.height == wh, @"Width and height of the image should be %.2f", wh); 34 | } 35 | 36 | - (void)testMultipleViews 37 | { 38 | ESMultipleArcProgressView *mv = [[ESMultipleArcProgressView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; 39 | 40 | ESArcProgressView *pv = [[ESArcProgressView alloc] init]; 41 | [pv setProgress:0.5]; 42 | [mv addArcProgressView:pv]; 43 | 44 | pv = [[ESArcProgressView alloc] init]; 45 | [pv setProgress:0.5]; 46 | [mv addArcProgressView:pv]; 47 | 48 | XCTAssert(mv.subviews.count == 2, @"ESMultipleArcProgressView should contain 2 subviews"); 49 | } 50 | 51 | - (void)testRemoveMultipleViews 52 | { 53 | ESMultipleArcProgressView *mv = [[ESMultipleArcProgressView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; 54 | 55 | ESArcProgressView *pv = [[ESArcProgressView alloc] init]; 56 | [pv setProgress:0.5]; 57 | [mv addArcProgressView:pv]; 58 | 59 | pv = [[ESArcProgressView alloc] init]; 60 | [pv setProgress:0.5]; 61 | [mv addArcProgressView:pv]; 62 | 63 | pv = [[ESArcProgressView alloc] init]; 64 | [pv setProgress:0.5]; 65 | [mv addArcProgressView:pv]; 66 | 67 | [mv removeArcProgressView:pv]; 68 | 69 | XCTAssert(mv.subviews.count == 2, @"ESMultipleArcProgressView should contain 2 subviews"); 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /ESArcProgressViewTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.esites.library.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, E-sites 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of ESArcProgressView nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, "7.0" 2 | source 'https://github.com/CocoaPods/Specs.git' 3 | 4 | link_with 'ESArcProgressView', 'ESArcProgressViewTests' 5 | 6 | pod 'ESArcProgressView', :path => "./ESArcProgressView.podspec" 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESArcProgressView 2 | [![Build](https://travis-ci.org/e-sites/ESArcProgressView.svg)](https://travis-ci.org/e-sites/ESArcProgressView) 3 | [![Platform](https://cocoapod-badges.herokuapp.com/p/ESArcProgressView/badge.png)](http://cocoadocs.org/docsets/ESArcProgressView) 4 | [![Version](https://cocoapod-badges.herokuapp.com/v/ESArcProgressView/badge.png)](http://cocoadocs.org/docsets/ESArcProgressView) 5 | 6 | A progress view to be used within Apple Watch projects 7 | 8 | ## Examples 9 | ![](https://raw.githubusercontent.com/e-sites/ESArcProgressView/master/Assets/example1.png) 10 | ![](https://raw.githubusercontent.com/e-sites/ESArcProgressView/master/Assets/applewatch1.png) 11 | 12 | 13 | ## Installation 14 | 15 | ### Cocoapods 16 | ```pod 'ESArcProgressView', '~> 1.4'``` 17 | 18 | ### Manually 19 | 20 | These classes have the following dependecies: 21 | - `QuartzCore` Framework 22 | 23 | ## Usage 24 | 25 | ### ESMultipleArcProgressView 26 | ```#import ``` 27 | 28 | ```objc 29 | ESMultipleArcProgressView *v = [[ESMultipleArcProgressView alloc] initWithFrame:CGRectMake(40, 40, 200, 200)]; 30 | [self.view addSubview:v]; 31 | 32 | ESArcProgressView *pv = [[ESArcProgressView alloc] init]; 33 | [pv setProgress:0.5]; 34 | [pv setText:@"RUN"]; 35 | [pv setColor:[UIColor orangeColor]]; 36 | [v addArcProgressView:pv]; 37 | 38 | pv = [[ESArcProgressView alloc] init]; 39 | [pv setProgress:0.65]; 40 | [pv setText:@"WALK"]; 41 | [pv setColor:[UIColor greenColor]]; 42 | [v addArcProgressView:pv]; 43 | 44 | pv = [[ESArcProgressView alloc] init]; 45 | [pv setProgress:0.8]; 46 | [pv setText:@"REST"]; 47 | [pv setColor:[UIColor redColor]]; 48 | [v addArcProgressView:pv]; 49 | ``` 50 | 51 | ```objc 52 | // To extract the UIImage: 53 | UIImage *image = [v es_imageOfView]; 54 | ``` 55 | 56 | ### ESArcProgressView 57 | ```#import ``` 58 | 59 | ```objc 60 | ESArcProgressView *pv = [[ESArcProgressView alloc] initWithFrame:CGRectMake(20, 20, 200, 200)]; 61 | [pv setProgress:0.5]; 62 | [pv setColor:[UIColor orangeColor]]; 63 | [self.view addSubview:pv]; 64 | ``` 65 | 66 | ```objc 67 | // To extract the UIImage: 68 | UIImage *image = [pv es_imageOfView]; 69 | ``` 70 | 71 | ### Animation 72 | 73 | ```#import ``` 74 | 75 | ```#include ``` 76 | 77 | ```objc 78 | ESArcProgressView *pv = [[ESArcProgressView alloc] initWithFrame:CGRectMake(20, 20, 200, 200)]; 79 | [pv setProgress:0]; 80 | [pv setColor:[UIColor orangeColor]]; 81 | [self.view addSubview:pv]; 82 | 83 | [pv animateTo:0.75 withDuration:1.0f withEasingFunction:BounceEaseOut withUpdateHandler:^(CGFloat animationProgress) { 84 | NSLog(@"animation progress: %.2f", animationProgress); 85 | if (animationProgress == 1.0f) { 86 | NSLog(@"animation finished"); 87 | } 88 | }]; 89 | ``` 90 | 91 | ## ESArcProgressView 92 | 93 | ### Properties 94 | 95 | | Property | Type | Description | Default value 96 | |------- |------ |---------- | ------- 97 | | `color` | UIColor | The color of the line | Green 98 | | `backgroundColor` | UIColor | The background color of the line | Default = 50% transparent of color 99 | | `dotColor ` | UIColor | The color of the center dot at the beginning / end of the line | White 100 | | `lineWidth` | CGFloat | The line width (aka diameter) of the line | 20 101 | | `showZeroProgress` | BOOL | Should a small line fragment be visible when the progress is 0.0 | NO 102 | | `showShadow` | BOOL | Should the line have a drop shadow | YES 103 | | `centerDotStyle` | ESArcProgress-CenterDotStyle | Center dot style placement | ESArcProgress-CenterDotStyle-BeginAndEnd 104 | | `centerDotImage` | UIImage | The 'center dot' is replaced by a custom image | nil 105 | | `colorizeCenterDotImage` | BOOL | Should `centerDotImage` be colorized with `dotColor` | YES 106 | | `progress` | CGFloat | The progress in percentage (from 0.0 - 1.0) | 0.0 107 | | `text` | NSString | Show a text label next to the progress view | nil 108 | | `multipleArcProgressView` | ESMultipleArc-ProgressView | The group view this instance belongs to | nil 109 | 110 | ### ESArcProgressCenterDotStyle 111 | ```objc 112 | typedef NS_ENUM(NSInteger, ESArcProgressCenterDotStyle) { 113 | ESArcProgressCenterDotStyleNone = 0, 114 | ESArcProgressCenterDotStyleBegin, 115 | ESArcProgressCenterDotStyleEnd, 116 | ESArcProgressCenterDotStyleBeginAndEnd 117 | }; 118 | ``` 119 | 120 | ### Methods 121 | 122 | #### `animateTo:` 123 | 124 | Animate to a given value with a duration of 1.0seconds and linear easing 125 | 126 | | Property | Type | Description 127 | |------- |------ |---------- 128 | | `toValue` | CGFloat | The progress to animate to 129 | 130 | ------------ 131 | 132 | #### `animateTo:withDuration:` 133 | 134 | Animate to a given value with a duration of 1.0seconds and linear easing 135 | 136 | | Property | Type | Description 137 | |------- |------ |---------- 138 | | `toValue` | CGFloat | The progress to animate to 139 | | `duration` | NSTimeInterval | The duration of the animation 140 | 141 | ------------ 142 | 143 | #### `animateTo:withDuration:withEasingFunction:` 144 | 145 | Animate to a given value with a duration of 1.0seconds and linear easing 146 | 147 | | Property | Type | Description 148 | |------- |------ |---------- 149 | | `toValue` | CGFloat | The progress to animate to 150 | | `duration` | NSTimeInterval | The duration of the animation 151 | | `easingFunction` | AHEasingFunction | See [AHEAsing](https://github.com/warrenm/AHEasing) for possible values 152 | 153 | ------------ 154 | 155 | #### `animateTo:withDuration:withEasingFunction:withUpdateHandler:` 156 | 157 | Animate to a given value with a duration of 1.0seconds and linear easing 158 | 159 | | Property | Type | Description 160 | |------- |------ |---------- 161 | | `toValue` | CGFloat | The progress to animate to 162 | | `duration` | NSTimeInterval | The duration of the animation 163 | | `easingFunction` | AHEasingFunction | See [AHEAsing](https://github.com/warrenm/AHEasing) for possible values 164 | | `updateHandler` | void (^)(CGFloat animationProgress) | Update block which is called when the animation progresses 165 | 166 | ------------ 167 | 168 | ## ESMultipleArcProgressView 169 | 170 | ### Properties 171 | 172 | | Property | Type | Description | Default value 173 | |------- |------ |---------- | ------- 174 | | `margin` | CGFloat | The space between the progress views | 1.0 175 | 176 | ### Methods 177 | 178 | ------------ 179 | 180 | #### `addArcProgressView:` 181 | 182 | Adds a `ESArcProgressView` to the view. Each `ESArcProgressView` will be inserted inside the previous `ESArcProgressView`. 183 | 184 | | Parameter | Type | Description 185 | |------- |------ |---------- 186 | | `progressView` | ESArcProgressView | The ESArcProgressView to add 187 | 188 | ------------ 189 | 190 | #### `removeArcProgressView:` 191 | 192 | Remove a particular `ESArcProgressView` from the view stack. This method will reposition the remaining progress views accordingly. 193 | 194 | | Parameter | Type | Description 195 | |------- |------ |---------- 196 | | `progressView` | ESArcProgressView | The ESArcProgressView to be removed 197 | 198 | 199 | ## UIView (ESMultipleArcProgressViewGenerateUIImage) 200 | 201 | #### `es_imageOfView` 202 | This method generates (and returns) a `UIImage` which is a snapshot of the current instance's view with the device's scale as setting 203 | 204 | ### `es_imageOfViewWithScale:` 205 | This method generates (and returns) a `UIImage` which is a snapshot of the current instance's view with a specific scale setting 206 | --------------------------------------------------------------------------------