├── .gitignore ├── Demo ├── THProgressView-Demo.xcodeproj │ └── project.pbxproj ├── THProgressView-Demo │ ├── THAppDelegate.h │ ├── THAppDelegate.m │ ├── THProgressView-Demo-Info.plist │ ├── THProgressView-Demo-Prefix.pch │ ├── THViewController.h │ ├── THViewController.m │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m └── THProgressView-DemoTests │ ├── THProgressView-DemoTests-Info.plist │ ├── THProgressView_DemoTests.m │ └── en.lproj │ └── InfoPlist.strings ├── LICENSE ├── README.md ├── Screenshot.png ├── THProgressView.podspec └── THProgressView ├── THProgressView.h └── THProgressView.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 925EF70918171635008A0A5B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925EF70818171635008A0A5B /* Foundation.framework */; }; 11 | 925EF70B18171635008A0A5B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925EF70A18171635008A0A5B /* CoreGraphics.framework */; }; 12 | 925EF70D18171635008A0A5B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925EF70C18171635008A0A5B /* UIKit.framework */; }; 13 | 925EF71318171635008A0A5B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 925EF71118171635008A0A5B /* InfoPlist.strings */; }; 14 | 925EF71518171635008A0A5B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 925EF71418171635008A0A5B /* main.m */; }; 15 | 925EF71918171635008A0A5B /* THAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 925EF71818171635008A0A5B /* THAppDelegate.m */; }; 16 | 925EF71F18171635008A0A5B /* THViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 925EF71E18171635008A0A5B /* THViewController.m */; }; 17 | 925EF72818171635008A0A5B /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925EF72718171635008A0A5B /* XCTest.framework */; }; 18 | 925EF72918171635008A0A5B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925EF70818171635008A0A5B /* Foundation.framework */; }; 19 | 925EF72A18171635008A0A5B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925EF70C18171635008A0A5B /* UIKit.framework */; }; 20 | 925EF73218171635008A0A5B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 925EF73018171635008A0A5B /* InfoPlist.strings */; }; 21 | 925EF73418171635008A0A5B /* THProgressView_DemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 925EF73318171635008A0A5B /* THProgressView_DemoTests.m */; }; 22 | 925EF740181716DA008A0A5B /* THProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 925EF73F181716DA008A0A5B /* THProgressView.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 925EF72B18171635008A0A5B /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 925EF6FD18171635008A0A5B /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 925EF70418171635008A0A5B; 31 | remoteInfo = "THProgressView-Demo"; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 925EF70518171635008A0A5B /* THProgressView-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "THProgressView-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 925EF70818171635008A0A5B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 38 | 925EF70A18171635008A0A5B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 39 | 925EF70C18171635008A0A5B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 40 | 925EF71018171635008A0A5B /* THProgressView-Demo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "THProgressView-Demo-Info.plist"; sourceTree = ""; }; 41 | 925EF71218171635008A0A5B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 42 | 925EF71418171635008A0A5B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 43 | 925EF71618171635008A0A5B /* THProgressView-Demo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "THProgressView-Demo-Prefix.pch"; sourceTree = ""; }; 44 | 925EF71718171635008A0A5B /* THAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THAppDelegate.h; sourceTree = ""; }; 45 | 925EF71818171635008A0A5B /* THAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THAppDelegate.m; sourceTree = ""; }; 46 | 925EF71D18171635008A0A5B /* THViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THViewController.h; sourceTree = ""; }; 47 | 925EF71E18171635008A0A5B /* THViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THViewController.m; sourceTree = ""; }; 48 | 925EF72618171635008A0A5B /* THProgressView-DemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "THProgressView-DemoTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 925EF72718171635008A0A5B /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 50 | 925EF72F18171635008A0A5B /* THProgressView-DemoTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "THProgressView-DemoTests-Info.plist"; sourceTree = ""; }; 51 | 925EF73118171635008A0A5B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 52 | 925EF73318171635008A0A5B /* THProgressView_DemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THProgressView_DemoTests.m; sourceTree = ""; }; 53 | 925EF73E181716DA008A0A5B /* THProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = THProgressView.h; path = ../THProgressView/THProgressView.h; sourceTree = ""; }; 54 | 925EF73F181716DA008A0A5B /* THProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = THProgressView.m; path = ../THProgressView/THProgressView.m; sourceTree = ""; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 925EF70218171635008A0A5B /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | 925EF70B18171635008A0A5B /* CoreGraphics.framework in Frameworks */, 63 | 925EF70D18171635008A0A5B /* UIKit.framework in Frameworks */, 64 | 925EF70918171635008A0A5B /* Foundation.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | 925EF72318171635008A0A5B /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | 925EF72818171635008A0A5B /* XCTest.framework in Frameworks */, 73 | 925EF72A18171635008A0A5B /* UIKit.framework in Frameworks */, 74 | 925EF72918171635008A0A5B /* Foundation.framework in Frameworks */, 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | 925EF6FC18171635008A0A5B = { 82 | isa = PBXGroup; 83 | children = ( 84 | 925EF73D181716C1008A0A5B /* THProgressView */, 85 | 925EF70E18171635008A0A5B /* THProgressView-Demo */, 86 | 925EF72D18171635008A0A5B /* THProgressView-DemoTests */, 87 | 925EF70718171635008A0A5B /* Frameworks */, 88 | 925EF70618171635008A0A5B /* Products */, 89 | ); 90 | sourceTree = ""; 91 | }; 92 | 925EF70618171635008A0A5B /* Products */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 925EF70518171635008A0A5B /* THProgressView-Demo.app */, 96 | 925EF72618171635008A0A5B /* THProgressView-DemoTests.xctest */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | 925EF70718171635008A0A5B /* Frameworks */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 925EF70818171635008A0A5B /* Foundation.framework */, 105 | 925EF70A18171635008A0A5B /* CoreGraphics.framework */, 106 | 925EF70C18171635008A0A5B /* UIKit.framework */, 107 | 925EF72718171635008A0A5B /* XCTest.framework */, 108 | ); 109 | name = Frameworks; 110 | sourceTree = ""; 111 | }; 112 | 925EF70E18171635008A0A5B /* THProgressView-Demo */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 925EF71718171635008A0A5B /* THAppDelegate.h */, 116 | 925EF71818171635008A0A5B /* THAppDelegate.m */, 117 | 925EF71D18171635008A0A5B /* THViewController.h */, 118 | 925EF71E18171635008A0A5B /* THViewController.m */, 119 | 925EF70F18171635008A0A5B /* Supporting Files */, 120 | ); 121 | path = "THProgressView-Demo"; 122 | sourceTree = ""; 123 | }; 124 | 925EF70F18171635008A0A5B /* Supporting Files */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 925EF71018171635008A0A5B /* THProgressView-Demo-Info.plist */, 128 | 925EF71118171635008A0A5B /* InfoPlist.strings */, 129 | 925EF71418171635008A0A5B /* main.m */, 130 | 925EF71618171635008A0A5B /* THProgressView-Demo-Prefix.pch */, 131 | ); 132 | name = "Supporting Files"; 133 | sourceTree = ""; 134 | }; 135 | 925EF72D18171635008A0A5B /* THProgressView-DemoTests */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 925EF73318171635008A0A5B /* THProgressView_DemoTests.m */, 139 | 925EF72E18171635008A0A5B /* Supporting Files */, 140 | ); 141 | path = "THProgressView-DemoTests"; 142 | sourceTree = ""; 143 | }; 144 | 925EF72E18171635008A0A5B /* Supporting Files */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 925EF72F18171635008A0A5B /* THProgressView-DemoTests-Info.plist */, 148 | 925EF73018171635008A0A5B /* InfoPlist.strings */, 149 | ); 150 | name = "Supporting Files"; 151 | sourceTree = ""; 152 | }; 153 | 925EF73D181716C1008A0A5B /* THProgressView */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 925EF73E181716DA008A0A5B /* THProgressView.h */, 157 | 925EF73F181716DA008A0A5B /* THProgressView.m */, 158 | ); 159 | name = THProgressView; 160 | sourceTree = ""; 161 | }; 162 | /* End PBXGroup section */ 163 | 164 | /* Begin PBXNativeTarget section */ 165 | 925EF70418171635008A0A5B /* THProgressView-Demo */ = { 166 | isa = PBXNativeTarget; 167 | buildConfigurationList = 925EF73718171635008A0A5B /* Build configuration list for PBXNativeTarget "THProgressView-Demo" */; 168 | buildPhases = ( 169 | 925EF70118171635008A0A5B /* Sources */, 170 | 925EF70218171635008A0A5B /* Frameworks */, 171 | 925EF70318171635008A0A5B /* Resources */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | ); 177 | name = "THProgressView-Demo"; 178 | productName = "THProgressView-Demo"; 179 | productReference = 925EF70518171635008A0A5B /* THProgressView-Demo.app */; 180 | productType = "com.apple.product-type.application"; 181 | }; 182 | 925EF72518171635008A0A5B /* THProgressView-DemoTests */ = { 183 | isa = PBXNativeTarget; 184 | buildConfigurationList = 925EF73A18171635008A0A5B /* Build configuration list for PBXNativeTarget "THProgressView-DemoTests" */; 185 | buildPhases = ( 186 | 925EF72218171635008A0A5B /* Sources */, 187 | 925EF72318171635008A0A5B /* Frameworks */, 188 | 925EF72418171635008A0A5B /* Resources */, 189 | ); 190 | buildRules = ( 191 | ); 192 | dependencies = ( 193 | 925EF72C18171635008A0A5B /* PBXTargetDependency */, 194 | ); 195 | name = "THProgressView-DemoTests"; 196 | productName = "THProgressView-DemoTests"; 197 | productReference = 925EF72618171635008A0A5B /* THProgressView-DemoTests.xctest */; 198 | productType = "com.apple.product-type.bundle.unit-test"; 199 | }; 200 | /* End PBXNativeTarget section */ 201 | 202 | /* Begin PBXProject section */ 203 | 925EF6FD18171635008A0A5B /* Project object */ = { 204 | isa = PBXProject; 205 | attributes = { 206 | CLASSPREFIX = TH; 207 | LastUpgradeCheck = 0500; 208 | ORGANIZATIONNAME = "Tiago Henriques"; 209 | TargetAttributes = { 210 | 925EF72518171635008A0A5B = { 211 | TestTargetID = 925EF70418171635008A0A5B; 212 | }; 213 | }; 214 | }; 215 | buildConfigurationList = 925EF70018171635008A0A5B /* Build configuration list for PBXProject "THProgressView-Demo" */; 216 | compatibilityVersion = "Xcode 3.2"; 217 | developmentRegion = English; 218 | hasScannedForEncodings = 0; 219 | knownRegions = ( 220 | en, 221 | Base, 222 | ); 223 | mainGroup = 925EF6FC18171635008A0A5B; 224 | productRefGroup = 925EF70618171635008A0A5B /* Products */; 225 | projectDirPath = ""; 226 | projectRoot = ""; 227 | targets = ( 228 | 925EF70418171635008A0A5B /* THProgressView-Demo */, 229 | 925EF72518171635008A0A5B /* THProgressView-DemoTests */, 230 | ); 231 | }; 232 | /* End PBXProject section */ 233 | 234 | /* Begin PBXResourcesBuildPhase section */ 235 | 925EF70318171635008A0A5B /* Resources */ = { 236 | isa = PBXResourcesBuildPhase; 237 | buildActionMask = 2147483647; 238 | files = ( 239 | 925EF71318171635008A0A5B /* InfoPlist.strings in Resources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | 925EF72418171635008A0A5B /* Resources */ = { 244 | isa = PBXResourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | 925EF73218171635008A0A5B /* InfoPlist.strings in Resources */, 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | }; 251 | /* End PBXResourcesBuildPhase section */ 252 | 253 | /* Begin PBXSourcesBuildPhase section */ 254 | 925EF70118171635008A0A5B /* Sources */ = { 255 | isa = PBXSourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | 925EF71F18171635008A0A5B /* THViewController.m in Sources */, 259 | 925EF71918171635008A0A5B /* THAppDelegate.m in Sources */, 260 | 925EF71518171635008A0A5B /* main.m in Sources */, 261 | 925EF740181716DA008A0A5B /* THProgressView.m in Sources */, 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | }; 265 | 925EF72218171635008A0A5B /* Sources */ = { 266 | isa = PBXSourcesBuildPhase; 267 | buildActionMask = 2147483647; 268 | files = ( 269 | 925EF73418171635008A0A5B /* THProgressView_DemoTests.m in Sources */, 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | /* End PBXSourcesBuildPhase section */ 274 | 275 | /* Begin PBXTargetDependency section */ 276 | 925EF72C18171635008A0A5B /* PBXTargetDependency */ = { 277 | isa = PBXTargetDependency; 278 | target = 925EF70418171635008A0A5B /* THProgressView-Demo */; 279 | targetProxy = 925EF72B18171635008A0A5B /* PBXContainerItemProxy */; 280 | }; 281 | /* End PBXTargetDependency section */ 282 | 283 | /* Begin PBXVariantGroup section */ 284 | 925EF71118171635008A0A5B /* InfoPlist.strings */ = { 285 | isa = PBXVariantGroup; 286 | children = ( 287 | 925EF71218171635008A0A5B /* en */, 288 | ); 289 | name = InfoPlist.strings; 290 | sourceTree = ""; 291 | }; 292 | 925EF73018171635008A0A5B /* InfoPlist.strings */ = { 293 | isa = PBXVariantGroup; 294 | children = ( 295 | 925EF73118171635008A0A5B /* en */, 296 | ); 297 | name = InfoPlist.strings; 298 | sourceTree = ""; 299 | }; 300 | /* End PBXVariantGroup section */ 301 | 302 | /* Begin XCBuildConfiguration section */ 303 | 925EF73518171635008A0A5B /* Debug */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ALWAYS_SEARCH_USER_PATHS = NO; 307 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 308 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 309 | CLANG_CXX_LIBRARY = "libc++"; 310 | CLANG_ENABLE_MODULES = YES; 311 | CLANG_ENABLE_OBJC_ARC = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_CONSTANT_CONVERSION = YES; 314 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 315 | CLANG_WARN_EMPTY_BODY = YES; 316 | CLANG_WARN_ENUM_CONVERSION = YES; 317 | CLANG_WARN_INT_CONVERSION = YES; 318 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 319 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 320 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 321 | COPY_PHASE_STRIP = NO; 322 | GCC_C_LANGUAGE_STANDARD = gnu99; 323 | GCC_DYNAMIC_NO_PIC = NO; 324 | GCC_OPTIMIZATION_LEVEL = 0; 325 | GCC_PREPROCESSOR_DEFINITIONS = ( 326 | "DEBUG=1", 327 | "$(inherited)", 328 | ); 329 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 330 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 331 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 332 | GCC_WARN_UNDECLARED_SELECTOR = YES; 333 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 334 | GCC_WARN_UNUSED_FUNCTION = YES; 335 | GCC_WARN_UNUSED_VARIABLE = YES; 336 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 337 | ONLY_ACTIVE_ARCH = YES; 338 | SDKROOT = iphoneos; 339 | }; 340 | name = Debug; 341 | }; 342 | 925EF73618171635008A0A5B /* Release */ = { 343 | isa = XCBuildConfiguration; 344 | buildSettings = { 345 | ALWAYS_SEARCH_USER_PATHS = NO; 346 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 347 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 348 | CLANG_CXX_LIBRARY = "libc++"; 349 | CLANG_ENABLE_MODULES = YES; 350 | CLANG_ENABLE_OBJC_ARC = YES; 351 | CLANG_WARN_BOOL_CONVERSION = YES; 352 | CLANG_WARN_CONSTANT_CONVERSION = YES; 353 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 354 | CLANG_WARN_EMPTY_BODY = YES; 355 | CLANG_WARN_ENUM_CONVERSION = YES; 356 | CLANG_WARN_INT_CONVERSION = YES; 357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 358 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 359 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 360 | COPY_PHASE_STRIP = YES; 361 | ENABLE_NS_ASSERTIONS = NO; 362 | GCC_C_LANGUAGE_STANDARD = gnu99; 363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 365 | GCC_WARN_UNDECLARED_SELECTOR = YES; 366 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 367 | GCC_WARN_UNUSED_FUNCTION = YES; 368 | GCC_WARN_UNUSED_VARIABLE = YES; 369 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 370 | SDKROOT = iphoneos; 371 | VALIDATE_PRODUCT = YES; 372 | }; 373 | name = Release; 374 | }; 375 | 925EF73818171635008A0A5B /* Debug */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 379 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 380 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 381 | GCC_PREFIX_HEADER = "THProgressView-Demo/THProgressView-Demo-Prefix.pch"; 382 | INFOPLIST_FILE = "THProgressView-Demo/THProgressView-Demo-Info.plist"; 383 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 384 | PRODUCT_NAME = "$(TARGET_NAME)"; 385 | WRAPPER_EXTENSION = app; 386 | }; 387 | name = Debug; 388 | }; 389 | 925EF73918171635008A0A5B /* Release */ = { 390 | isa = XCBuildConfiguration; 391 | buildSettings = { 392 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 393 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 394 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 395 | GCC_PREFIX_HEADER = "THProgressView-Demo/THProgressView-Demo-Prefix.pch"; 396 | INFOPLIST_FILE = "THProgressView-Demo/THProgressView-Demo-Info.plist"; 397 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 398 | PRODUCT_NAME = "$(TARGET_NAME)"; 399 | WRAPPER_EXTENSION = app; 400 | }; 401 | name = Release; 402 | }; 403 | 925EF73B18171635008A0A5B /* Debug */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 407 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/THProgressView-Demo.app/THProgressView-Demo"; 408 | FRAMEWORK_SEARCH_PATHS = ( 409 | "$(SDKROOT)/Developer/Library/Frameworks", 410 | "$(inherited)", 411 | "$(DEVELOPER_FRAMEWORKS_DIR)", 412 | ); 413 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 414 | GCC_PREFIX_HEADER = "THProgressView-Demo/THProgressView-Demo-Prefix.pch"; 415 | GCC_PREPROCESSOR_DEFINITIONS = ( 416 | "DEBUG=1", 417 | "$(inherited)", 418 | ); 419 | INFOPLIST_FILE = "THProgressView-DemoTests/THProgressView-DemoTests-Info.plist"; 420 | PRODUCT_NAME = "$(TARGET_NAME)"; 421 | TEST_HOST = "$(BUNDLE_LOADER)"; 422 | WRAPPER_EXTENSION = xctest; 423 | }; 424 | name = Debug; 425 | }; 426 | 925EF73C18171635008A0A5B /* Release */ = { 427 | isa = XCBuildConfiguration; 428 | buildSettings = { 429 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 430 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/THProgressView-Demo.app/THProgressView-Demo"; 431 | FRAMEWORK_SEARCH_PATHS = ( 432 | "$(SDKROOT)/Developer/Library/Frameworks", 433 | "$(inherited)", 434 | "$(DEVELOPER_FRAMEWORKS_DIR)", 435 | ); 436 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 437 | GCC_PREFIX_HEADER = "THProgressView-Demo/THProgressView-Demo-Prefix.pch"; 438 | INFOPLIST_FILE = "THProgressView-DemoTests/THProgressView-DemoTests-Info.plist"; 439 | PRODUCT_NAME = "$(TARGET_NAME)"; 440 | TEST_HOST = "$(BUNDLE_LOADER)"; 441 | WRAPPER_EXTENSION = xctest; 442 | }; 443 | name = Release; 444 | }; 445 | /* End XCBuildConfiguration section */ 446 | 447 | /* Begin XCConfigurationList section */ 448 | 925EF70018171635008A0A5B /* Build configuration list for PBXProject "THProgressView-Demo" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 925EF73518171635008A0A5B /* Debug */, 452 | 925EF73618171635008A0A5B /* Release */, 453 | ); 454 | defaultConfigurationIsVisible = 0; 455 | defaultConfigurationName = Release; 456 | }; 457 | 925EF73718171635008A0A5B /* Build configuration list for PBXNativeTarget "THProgressView-Demo" */ = { 458 | isa = XCConfigurationList; 459 | buildConfigurations = ( 460 | 925EF73818171635008A0A5B /* Debug */, 461 | 925EF73918171635008A0A5B /* Release */, 462 | ); 463 | defaultConfigurationIsVisible = 0; 464 | defaultConfigurationName = Release; 465 | }; 466 | 925EF73A18171635008A0A5B /* Build configuration list for PBXNativeTarget "THProgressView-DemoTests" */ = { 467 | isa = XCConfigurationList; 468 | buildConfigurations = ( 469 | 925EF73B18171635008A0A5B /* Debug */, 470 | 925EF73C18171635008A0A5B /* Release */, 471 | ); 472 | defaultConfigurationIsVisible = 0; 473 | defaultConfigurationName = Release; 474 | }; 475 | /* End XCConfigurationList section */ 476 | }; 477 | rootObject = 925EF6FD18171635008A0A5B /* Project object */; 478 | } 479 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo/THAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // THAppDelegate.h 3 | // THProgressView-Demo 4 | // 5 | // Created by Tiago Henriques on 10/22/13. 6 | // Copyright (c) 2013 Tiago Henriques. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface THAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo/THAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // THAppDelegate.m 3 | // THProgressView-Demo 4 | // 5 | // Created by Tiago Henriques on 10/22/13. 6 | // Copyright (c) 2013 Tiago Henriques. All rights reserved. 7 | // 8 | 9 | #import "THAppDelegate.h" 10 | #import "THViewController.h" 11 | 12 | @implementation THAppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 15 | { 16 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 17 | self.window.rootViewController = [THViewController new]; 18 | [self.window makeKeyAndVisible]; 19 | return YES; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo/THProgressView-Demo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.tiagomnh.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo/THProgressView-Demo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo/THViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // THViewController.h 3 | // THProgressView-Demo 4 | // 5 | // Created by Tiago Henriques on 10/22/13. 6 | // Copyright (c) 2013 Tiago Henriques. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface THViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo/THViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // THViewController.m 3 | // THProgressView-Demo 4 | // 5 | // Created by Tiago Henriques on 10/22/13. 6 | // Copyright (c) 2013 Tiago Henriques. All rights reserved. 7 | // 8 | 9 | #import "THViewController.h" 10 | #import "THProgressView.h" 11 | 12 | 13 | #define DEFAULT_BLUE [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0] 14 | 15 | 16 | static const CGSize progressViewSize = { 200.0f, 30.0f }; 17 | 18 | 19 | @interface THViewController () 20 | @property (nonatomic) CGFloat progress; 21 | @property (nonatomic, strong) NSTimer *timer; 22 | @property (nonatomic, strong) NSArray *progressViews; 23 | @end 24 | 25 | 26 | @implementation THViewController 27 | 28 | - (void)viewDidLoad 29 | { 30 | UIView *topView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetMidY(self.view.bounds))]; 31 | topView.backgroundColor = [UIColor blackColor]; 32 | 33 | THProgressView *topProgressView = [[THProgressView alloc] initWithFrame:CGRectMake(CGRectGetMidX(topView.frame) - progressViewSize.width / 2.0f, 34 | CGRectGetMidY(topView.frame) - progressViewSize.height / 2.0f, 35 | progressViewSize.width, 36 | progressViewSize.height)]; 37 | topProgressView.borderTintColor = [UIColor whiteColor]; 38 | topProgressView.progressTintColor = [UIColor whiteColor]; 39 | topProgressView.progressBackgroundColor = [UIColor redColor]; 40 | [topView addSubview:topProgressView]; 41 | [self.view addSubview:topView]; 42 | 43 | 44 | 45 | UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetMidY(self.view.bounds), CGRectGetWidth(self.view.bounds), CGRectGetMidY(self.view.bounds))]; 46 | bottomView.backgroundColor = [UIColor whiteColor]; 47 | 48 | THProgressView *bottomProgressView = [[THProgressView alloc] initWithFrame:CGRectMake(CGRectGetMidX(bottomView.frame) - progressViewSize.width / 2.0f, 49 | CGRectGetMidY(topView.frame) - progressViewSize.height / 2.0f, 50 | progressViewSize.width, 51 | progressViewSize.height)]; 52 | bottomProgressView.borderTintColor = DEFAULT_BLUE; 53 | bottomProgressView.progressTintColor = DEFAULT_BLUE; 54 | bottomProgressView.progressBackgroundColor = [UIColor greenColor]; 55 | [bottomView addSubview:bottomProgressView]; 56 | [self.view addSubview:bottomView]; 57 | 58 | 59 | self.progressViews = @[ topProgressView, bottomProgressView ]; 60 | 61 | self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES]; 62 | } 63 | 64 | - (void)updateProgress 65 | { 66 | self.progress += 0.20f; 67 | if (self.progress > 1.0f) { 68 | self.progress = 0; 69 | } 70 | 71 | [self.progressViews enumerateObjectsUsingBlock:^(THProgressView *progressView, NSUInteger idx, BOOL *stop) { 72 | [progressView setProgress:self.progress animated:YES]; 73 | }]; 74 | } 75 | 76 | - (UIStatusBarStyle)preferredStatusBarStyle 77 | { 78 | return UIStatusBarStyleLightContent; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Demo/THProgressView-Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // THProgressView-Demo 4 | // 5 | // Created by Tiago Henriques on 10/22/13. 6 | // Copyright (c) 2013 Tiago Henriques. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "THAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([THAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Demo/THProgressView-DemoTests/THProgressView-DemoTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.tiagomnh.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Demo/THProgressView-DemoTests/THProgressView_DemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // THProgressView_DemoTests.m 3 | // THProgressView-DemoTests 4 | // 5 | // Created by Tiago Henriques on 10/22/13. 6 | // Copyright (c) 2013 Tiago Henriques. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface THProgressView_DemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation THProgressView_DemoTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Demo/THProgressView-DemoTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Tiago Henriques (http://tiagomnh.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THProgressView 2 | 3 | `UIView` subclass that mimics the progress bar of Twitter for iOS 4 | 5 | ![Screenshot](Screenshot.png) 6 | 7 | ## Installation 8 | 9 | The preferred way is through [CocoaPods](http://cocoapods.org/?q=THProgressView). Just add the following line to your Podfile: 10 | 11 | `pod 'THProgressView', '~> 1.0'` 12 | 13 | You can also do it manually by dragging the contents of `THProgressView/` into your project. 14 | 15 | ## Usage 16 | 17 | `THProgressView` is simply a `UIView` subclass so just instantiate it and add it a view hieararchy. 18 | 19 | ```objc 20 | CGRect rect = ... 21 | THProgressView *progressView = [[THProgressView alloc] initWithFrame:rect]; 22 | progressView.borderTintColor = [UIColor whiteColor]; 23 | progressView.progressTintColor = [UIColor whiteColor]; 24 | [progressView setProgress:0.5f animated:YES]; // floating-point value between 0.0 and 1.0 25 | ``` 26 | 27 | The sample project in `/Demo` contains a couple examples. 28 | 29 | ## License 30 | 31 | THProgressView is available under the MIT license. See the LICENSE file for more info. 32 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiagomnh/THProgressView/0801d83a97efebbe6e46ff329453a565c918aa1c/Screenshot.png -------------------------------------------------------------------------------- /THProgressView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "THProgressView" 3 | s.version = "1.0" 4 | s.summary = "UIView subclass that mimics the progress bar of Twitter for iOS." 5 | s.homepage = "https://github.com/tiagomnh/THProgressView" 6 | s.screenshots = "https://raw.github.com/tiagomnh/THProgressView/master/Screenshot.png" 7 | 8 | s.license = { :type => 'MIT', :file => 'LICENSE' } 9 | s.author = { "Tiago Henriques" => "tiagomnh@gmail.com" } 10 | s.source = { :git => "https://github.com/tiagomnh/THProgressView.git", :tag => "1.0" } 11 | 12 | s.platform = :ios, '6.0' 13 | s.source_files = 'THProgressView/*.{h,m}' 14 | s.requires_arc = true 15 | end -------------------------------------------------------------------------------- /THProgressView/THProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // THProgressView.h 3 | // 4 | // Created by Tiago Henriques on 10/22/13. 5 | // Copyright (c) 2013 Tiago Henriques. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface THProgressView : UIView 11 | 12 | @property (nonatomic, strong) UIColor* progressTintColor; 13 | @property (nonatomic, strong) UIColor* borderTintColor; 14 | @property (nonatomic, strong) UIColor* progressBackgroundColor; 15 | @property (nonatomic) CGFloat progress; 16 | 17 | - (void)setProgress:(CGFloat)progress animated:(BOOL)animated; 18 | 19 | @end -------------------------------------------------------------------------------- /THProgressView/THProgressView.m: -------------------------------------------------------------------------------- 1 | // 2 | // THProgressView.m 3 | // 4 | // Created by Tiago Henriques on 10/22/13. 5 | // Copyright (c) 2013 Tiago Henriques. All rights reserved. 6 | // 7 | 8 | #import "THProgressView.h" 9 | 10 | #import 11 | 12 | 13 | static const CGFloat kBorderWidth = 2.0f; 14 | 15 | 16 | #pragma mark - 17 | #pragma mark THProgressLayer 18 | 19 | @interface THProgressLayer : CALayer 20 | @property (nonatomic, strong) UIColor* progressTintColor; 21 | @property (nonatomic, strong) UIColor* borderTintColor; 22 | @property (nonatomic, strong) UIColor* progressBackgroundColor; 23 | @property (nonatomic) CGFloat progress; 24 | @end 25 | 26 | @implementation THProgressLayer 27 | 28 | @dynamic progressTintColor; 29 | @dynamic borderTintColor; 30 | @dynamic progressBackgroundColor; 31 | 32 | + (BOOL)needsDisplayForKey:(NSString *)key 33 | { 34 | return [key isEqualToString:@"progress"] ? YES : [super needsDisplayForKey:key]; 35 | } 36 | 37 | - (void)drawInContext:(CGContextRef)context 38 | { 39 | CGRect rect = CGRectInset(self.bounds, kBorderWidth, kBorderWidth); 40 | CGFloat radius = CGRectGetHeight(rect) / 2.0f; 41 | CGContextSetLineWidth(context, kBorderWidth); 42 | CGContextSetStrokeColorWithColor(context, self.borderTintColor.CGColor); 43 | [self drawRectangleInContext:context inRect:rect withRadius:radius]; 44 | CGContextStrokePath(context); 45 | 46 | CGContextSetFillColorWithColor(context, self.progressTintColor.CGColor); 47 | CGRect progressRect = CGRectInset(rect, 2 * kBorderWidth, 2 * kBorderWidth); 48 | CGFloat progressRadius = CGRectGetHeight(progressRect) / 2.0f; 49 | progressRect.size.width = fmaxf(self.progress * progressRect.size.width, 2.0f * progressRadius); 50 | [self drawRectangleInContext:context inRect:progressRect withRadius:progressRadius]; 51 | CGContextFillPath(context); 52 | 53 | CGContextSetFillColorWithColor(context, self.progressBackgroundColor.CGColor); 54 | CGRect progressBackgroundRect = progressRect; 55 | progressBackgroundRect.size.width = rect.size.width - 4 * kBorderWidth - progressRect.size.width; 56 | progressBackgroundRect.origin.x = progressRect.origin.x + progressRect.size.width; 57 | [self drawProgressBackgroundRectangleInContext:context inRect:progressBackgroundRect withRadius:progressRadius]; 58 | CGContextFillPath(context); 59 | } 60 | 61 | - (void)drawRectangleInContext:(CGContextRef)context inRect:(CGRect)rect withRadius:(CGFloat)radius 62 | { 63 | CGContextBeginPath(context); 64 | CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius); 65 | CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius); 66 | CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI / 2, 1); 67 | 68 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height); 69 | CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1); 70 | 71 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + radius); 72 | CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, radius, 0.0f, -M_PI / 2, 1); 73 | 74 | CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y); 75 | CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, -M_PI / 2, -M_PI, 1); 76 | CGContextClosePath(context); 77 | } 78 | 79 | - (void)drawProgressBackgroundRectangleInContext:(CGContextRef)context inRect:(CGRect)rect withRadius:(CGFloat)radius 80 | { 81 | CGContextBeginPath(context); 82 | CGContextMoveToPoint(context, rect.origin.x - radius, rect.origin.y); 83 | CGContextAddArc(context, rect.origin.x - radius, rect.origin.y + radius, radius, 3 * M_PI / 2, 2 * M_PI, 0); 84 | CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius); 85 | 86 | CGContextAddArc(context, rect.origin.x - radius, rect.origin.y + rect.size.height - radius, radius, 0.0f, M_PI / 2, 0); 87 | CGContextMoveToPoint(context, rect.origin.x - radius, rect.origin.y + rect.size.height); 88 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height); 89 | 90 | CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1); 91 | CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + radius); 92 | 93 | CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, radius, 2 * M_PI, 3 * M_PI / 2, 1); 94 | CGContextAddLineToPoint(context, rect.origin.x - radius, rect.origin.y); 95 | CGContextClosePath(context); 96 | } 97 | 98 | @end 99 | 100 | 101 | #pragma mark - 102 | #pragma mark THProgressView 103 | 104 | @implementation THProgressView 105 | 106 | - (id)initWithFrame:(CGRect)frame 107 | { 108 | if (self = [super initWithFrame:frame]) { 109 | [self initialize]; 110 | } 111 | return self; 112 | } 113 | 114 | - (id)initWithCoder:(NSCoder *)aDecoder 115 | { 116 | if (self = [super initWithCoder:aDecoder]) { 117 | [self initialize]; 118 | } 119 | return self; 120 | } 121 | 122 | - (void)initialize 123 | { 124 | self.backgroundColor = [UIColor clearColor]; 125 | } 126 | 127 | - (void)didMoveToWindow 128 | { 129 | self.progressLayer.contentsScale = self.window.screen.scale; 130 | } 131 | 132 | + (Class)layerClass 133 | { 134 | return [THProgressLayer class]; 135 | } 136 | 137 | - (THProgressLayer *)progressLayer 138 | { 139 | return (THProgressLayer *)self.layer; 140 | } 141 | 142 | 143 | #pragma mark Getters & Setters 144 | 145 | - (CGFloat)progress 146 | { 147 | return self.progressLayer.progress; 148 | } 149 | 150 | - (void)setProgress:(CGFloat)progress 151 | { 152 | [self setProgress:progress animated:NO]; 153 | } 154 | 155 | - (void)setProgress:(CGFloat)progress animated:(BOOL)animated 156 | { 157 | [self.progressLayer removeAnimationForKey:@"progress"]; 158 | CGFloat pinnedProgress = MIN(MAX(progress, 0.0f), 1.0f); 159 | 160 | if (animated) { 161 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"progress"]; 162 | animation.duration = fabsf(self.progress - pinnedProgress) + 0.1f; 163 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 164 | animation.fromValue = [NSNumber numberWithFloat:self.progress]; 165 | animation.toValue = [NSNumber numberWithFloat:pinnedProgress]; 166 | [self.progressLayer addAnimation:animation forKey:@"progress"]; 167 | } 168 | else { 169 | [self.progressLayer setNeedsDisplay]; 170 | } 171 | 172 | self.progressLayer.progress = pinnedProgress; 173 | } 174 | 175 | - (UIColor *)progressTintColor 176 | { 177 | return self.progressLayer.progressTintColor; 178 | } 179 | 180 | - (void)setProgressTintColor:(UIColor *)progressTintColor 181 | { 182 | self.progressLayer.progressTintColor = progressTintColor; 183 | [self.progressLayer setNeedsDisplay]; 184 | } 185 | 186 | - (UIColor *)borderTintColor 187 | { 188 | return self.progressLayer.borderTintColor; 189 | } 190 | 191 | - (void)setBorderTintColor:(UIColor *)borderTintColor 192 | { 193 | self.progressLayer.borderTintColor = borderTintColor; 194 | [self.progressLayer setNeedsDisplay]; 195 | } 196 | 197 | - (UIColor *)progressBackgroundColor 198 | { 199 | return self.progressLayer.progressBackgroundColor; 200 | } 201 | 202 | - (void)setProgressBackgroundColor:(UIColor *)backgroundColor 203 | { 204 | self.progressLayer.progressBackgroundColor = backgroundColor; 205 | [self.progressLayer setNeedsDisplay]; 206 | } 207 | 208 | @end 209 | --------------------------------------------------------------------------------