├── .gitignore ├── ElegantProgress.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── ElegantProgress.xccheckout │ └── xcuserdata │ │ └── wayne.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── wayne.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── ElegantProgress.xcscheme │ └── xcschememanagement.plist ├── ElegantProgress ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ElegantProgressView.swift ├── Info.plist ├── InnerShadowLayer.swift ├── UIColor+Ex.swift └── ViewController.swift ├── README.md └── demo.m4v /.gitignore: -------------------------------------------------------------------------------- 1 | Build 2 | .git 3 | -------------------------------------------------------------------------------- /ElegantProgress.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B081FFB31B31193100BDA08D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B081FFB21B31193100BDA08D /* AppDelegate.swift */; }; 11 | B081FFB51B31193100BDA08D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B081FFB41B31193100BDA08D /* ViewController.swift */; }; 12 | B081FFB81B31193100BDA08D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B081FFB61B31193100BDA08D /* Main.storyboard */; }; 13 | B081FFBA1B31193100BDA08D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B081FFB91B31193100BDA08D /* Assets.xcassets */; }; 14 | B081FFBD1B31193100BDA08D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B081FFBB1B31193100BDA08D /* LaunchScreen.storyboard */; }; 15 | B081FFC51B3119E500BDA08D /* ElegantProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B081FFC41B3119E500BDA08D /* ElegantProgressView.swift */; }; 16 | B081FFC71B311D9700BDA08D /* UIColor+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = B081FFC61B311D9700BDA08D /* UIColor+Ex.swift */; }; 17 | B081FFC91B312E9E00BDA08D /* InnerShadowLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B081FFC81B312E9D00BDA08D /* InnerShadowLayer.swift */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | B081FFAF1B31193100BDA08D /* ElegantProgress.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ElegantProgress.app; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | B081FFB21B31193100BDA08D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 23 | B081FFB41B31193100BDA08D /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 24 | B081FFB71B31193100BDA08D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 25 | B081FFB91B31193100BDA08D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 26 | B081FFBC1B31193100BDA08D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 27 | B081FFBE1B31193100BDA08D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 28 | B081FFC41B3119E500BDA08D /* ElegantProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ElegantProgressView.swift; sourceTree = ""; }; 29 | B081FFC61B311D9700BDA08D /* UIColor+Ex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Ex.swift"; sourceTree = ""; }; 30 | B081FFC81B312E9D00BDA08D /* InnerShadowLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InnerShadowLayer.swift; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | B081FFAC1B31193100BDA08D /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | B081FFA61B31193100BDA08D = { 45 | isa = PBXGroup; 46 | children = ( 47 | B081FFB11B31193100BDA08D /* ElegantProgress */, 48 | B081FFB01B31193100BDA08D /* Products */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | B081FFB01B31193100BDA08D /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | B081FFAF1B31193100BDA08D /* ElegantProgress.app */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | B081FFB11B31193100BDA08D /* ElegantProgress */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | B081FFB21B31193100BDA08D /* AppDelegate.swift */, 64 | B081FFB41B31193100BDA08D /* ViewController.swift */, 65 | B081FFC61B311D9700BDA08D /* UIColor+Ex.swift */, 66 | B081FFC41B3119E500BDA08D /* ElegantProgressView.swift */, 67 | B081FFC81B312E9D00BDA08D /* InnerShadowLayer.swift */, 68 | B081FFB61B31193100BDA08D /* Main.storyboard */, 69 | B081FFB91B31193100BDA08D /* Assets.xcassets */, 70 | B081FFBB1B31193100BDA08D /* LaunchScreen.storyboard */, 71 | B081FFBE1B31193100BDA08D /* Info.plist */, 72 | ); 73 | path = ElegantProgress; 74 | sourceTree = ""; 75 | }; 76 | /* End PBXGroup section */ 77 | 78 | /* Begin PBXNativeTarget section */ 79 | B081FFAE1B31193100BDA08D /* ElegantProgress */ = { 80 | isa = PBXNativeTarget; 81 | buildConfigurationList = B081FFC11B31193100BDA08D /* Build configuration list for PBXNativeTarget "ElegantProgress" */; 82 | buildPhases = ( 83 | B081FFAB1B31193100BDA08D /* Sources */, 84 | B081FFAC1B31193100BDA08D /* Frameworks */, 85 | B081FFAD1B31193100BDA08D /* Resources */, 86 | ); 87 | buildRules = ( 88 | ); 89 | dependencies = ( 90 | ); 91 | name = ElegantProgress; 92 | productName = ElegantProgress; 93 | productReference = B081FFAF1B31193100BDA08D /* ElegantProgress.app */; 94 | productType = "com.apple.product-type.application"; 95 | }; 96 | /* End PBXNativeTarget section */ 97 | 98 | /* Begin PBXProject section */ 99 | B081FFA71B31193100BDA08D /* Project object */ = { 100 | isa = PBXProject; 101 | attributes = { 102 | LastUpgradeCheck = 0700; 103 | ORGANIZATIONNAME = wayne; 104 | TargetAttributes = { 105 | B081FFAE1B31193100BDA08D = { 106 | CreatedOnToolsVersion = 7.0; 107 | }; 108 | }; 109 | }; 110 | buildConfigurationList = B081FFAA1B31193100BDA08D /* Build configuration list for PBXProject "ElegantProgress" */; 111 | compatibilityVersion = "Xcode 3.2"; 112 | developmentRegion = English; 113 | hasScannedForEncodings = 0; 114 | knownRegions = ( 115 | en, 116 | Base, 117 | ); 118 | mainGroup = B081FFA61B31193100BDA08D; 119 | productRefGroup = B081FFB01B31193100BDA08D /* Products */; 120 | projectDirPath = ""; 121 | projectRoot = ""; 122 | targets = ( 123 | B081FFAE1B31193100BDA08D /* ElegantProgress */, 124 | ); 125 | }; 126 | /* End PBXProject section */ 127 | 128 | /* Begin PBXResourcesBuildPhase section */ 129 | B081FFAD1B31193100BDA08D /* Resources */ = { 130 | isa = PBXResourcesBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | B081FFBD1B31193100BDA08D /* LaunchScreen.storyboard in Resources */, 134 | B081FFBA1B31193100BDA08D /* Assets.xcassets in Resources */, 135 | B081FFB81B31193100BDA08D /* Main.storyboard in Resources */, 136 | ); 137 | runOnlyForDeploymentPostprocessing = 0; 138 | }; 139 | /* End PBXResourcesBuildPhase section */ 140 | 141 | /* Begin PBXSourcesBuildPhase section */ 142 | B081FFAB1B31193100BDA08D /* Sources */ = { 143 | isa = PBXSourcesBuildPhase; 144 | buildActionMask = 2147483647; 145 | files = ( 146 | B081FFC71B311D9700BDA08D /* UIColor+Ex.swift in Sources */, 147 | B081FFC51B3119E500BDA08D /* ElegantProgressView.swift in Sources */, 148 | B081FFB51B31193100BDA08D /* ViewController.swift in Sources */, 149 | B081FFC91B312E9E00BDA08D /* InnerShadowLayer.swift in Sources */, 150 | B081FFB31B31193100BDA08D /* AppDelegate.swift in Sources */, 151 | ); 152 | runOnlyForDeploymentPostprocessing = 0; 153 | }; 154 | /* End PBXSourcesBuildPhase section */ 155 | 156 | /* Begin PBXVariantGroup section */ 157 | B081FFB61B31193100BDA08D /* Main.storyboard */ = { 158 | isa = PBXVariantGroup; 159 | children = ( 160 | B081FFB71B31193100BDA08D /* Base */, 161 | ); 162 | name = Main.storyboard; 163 | sourceTree = ""; 164 | }; 165 | B081FFBB1B31193100BDA08D /* LaunchScreen.storyboard */ = { 166 | isa = PBXVariantGroup; 167 | children = ( 168 | B081FFBC1B31193100BDA08D /* Base */, 169 | ); 170 | name = LaunchScreen.storyboard; 171 | sourceTree = ""; 172 | }; 173 | /* End PBXVariantGroup section */ 174 | 175 | /* Begin XCBuildConfiguration section */ 176 | B081FFBF1B31193100BDA08D /* Debug */ = { 177 | isa = XCBuildConfiguration; 178 | buildSettings = { 179 | ALWAYS_SEARCH_USER_PATHS = NO; 180 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 181 | CLANG_CXX_LIBRARY = "libc++"; 182 | CLANG_ENABLE_MODULES = YES; 183 | CLANG_ENABLE_OBJC_ARC = YES; 184 | CLANG_WARN_BOOL_CONVERSION = YES; 185 | CLANG_WARN_CONSTANT_CONVERSION = YES; 186 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 187 | CLANG_WARN_EMPTY_BODY = YES; 188 | CLANG_WARN_ENUM_CONVERSION = YES; 189 | CLANG_WARN_INT_CONVERSION = YES; 190 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 191 | CLANG_WARN_UNREACHABLE_CODE = YES; 192 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 193 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 194 | COPY_PHASE_STRIP = NO; 195 | DEBUG_INFORMATION_FORMAT = dwarf; 196 | ENABLE_STRICT_OBJC_MSGSEND = YES; 197 | ENABLE_TESTABILITY = YES; 198 | GCC_C_LANGUAGE_STANDARD = gnu99; 199 | GCC_DYNAMIC_NO_PIC = NO; 200 | GCC_NO_COMMON_BLOCKS = YES; 201 | GCC_OPTIMIZATION_LEVEL = 0; 202 | GCC_PREPROCESSOR_DEFINITIONS = ( 203 | "DEBUG=1", 204 | "$(inherited)", 205 | ); 206 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 207 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 208 | GCC_WARN_UNDECLARED_SELECTOR = YES; 209 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 210 | GCC_WARN_UNUSED_FUNCTION = YES; 211 | GCC_WARN_UNUSED_VARIABLE = YES; 212 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 213 | MTL_ENABLE_DEBUG_INFO = YES; 214 | ONLY_ACTIVE_ARCH = YES; 215 | SDKROOT = iphoneos; 216 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 217 | TARGETED_DEVICE_FAMILY = "1,2"; 218 | }; 219 | name = Debug; 220 | }; 221 | B081FFC01B31193100BDA08D /* Release */ = { 222 | isa = XCBuildConfiguration; 223 | buildSettings = { 224 | ALWAYS_SEARCH_USER_PATHS = NO; 225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 226 | CLANG_CXX_LIBRARY = "libc++"; 227 | CLANG_ENABLE_MODULES = YES; 228 | CLANG_ENABLE_OBJC_ARC = YES; 229 | CLANG_WARN_BOOL_CONVERSION = YES; 230 | CLANG_WARN_CONSTANT_CONVERSION = YES; 231 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 232 | CLANG_WARN_EMPTY_BODY = YES; 233 | CLANG_WARN_ENUM_CONVERSION = YES; 234 | CLANG_WARN_INT_CONVERSION = YES; 235 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 236 | CLANG_WARN_UNREACHABLE_CODE = YES; 237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 238 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 239 | COPY_PHASE_STRIP = NO; 240 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 241 | ENABLE_NS_ASSERTIONS = NO; 242 | ENABLE_STRICT_OBJC_MSGSEND = YES; 243 | GCC_C_LANGUAGE_STANDARD = gnu99; 244 | GCC_NO_COMMON_BLOCKS = YES; 245 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 246 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 247 | GCC_WARN_UNDECLARED_SELECTOR = YES; 248 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 249 | GCC_WARN_UNUSED_FUNCTION = YES; 250 | GCC_WARN_UNUSED_VARIABLE = YES; 251 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 252 | MTL_ENABLE_DEBUG_INFO = NO; 253 | SDKROOT = iphoneos; 254 | TARGETED_DEVICE_FAMILY = "1,2"; 255 | VALIDATE_PRODUCT = YES; 256 | }; 257 | name = Release; 258 | }; 259 | B081FFC21B31193100BDA08D /* Debug */ = { 260 | isa = XCBuildConfiguration; 261 | buildSettings = { 262 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 263 | INFOPLIST_FILE = ElegantProgress/Info.plist; 264 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 265 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 266 | PRODUCT_BUNDLE_IDENTIFIER = wayne.ElegantProgress; 267 | PRODUCT_NAME = "$(TARGET_NAME)"; 268 | }; 269 | name = Debug; 270 | }; 271 | B081FFC31B31193100BDA08D /* Release */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 275 | INFOPLIST_FILE = ElegantProgress/Info.plist; 276 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 277 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 278 | PRODUCT_BUNDLE_IDENTIFIER = wayne.ElegantProgress; 279 | PRODUCT_NAME = "$(TARGET_NAME)"; 280 | }; 281 | name = Release; 282 | }; 283 | /* End XCBuildConfiguration section */ 284 | 285 | /* Begin XCConfigurationList section */ 286 | B081FFAA1B31193100BDA08D /* Build configuration list for PBXProject "ElegantProgress" */ = { 287 | isa = XCConfigurationList; 288 | buildConfigurations = ( 289 | B081FFBF1B31193100BDA08D /* Debug */, 290 | B081FFC01B31193100BDA08D /* Release */, 291 | ); 292 | defaultConfigurationIsVisible = 0; 293 | defaultConfigurationName = Release; 294 | }; 295 | B081FFC11B31193100BDA08D /* Build configuration list for PBXNativeTarget "ElegantProgress" */ = { 296 | isa = XCConfigurationList; 297 | buildConfigurations = ( 298 | B081FFC21B31193100BDA08D /* Debug */, 299 | B081FFC31B31193100BDA08D /* Release */, 300 | ); 301 | defaultConfigurationIsVisible = 0; 302 | }; 303 | /* End XCConfigurationList section */ 304 | }; 305 | rootObject = B081FFA71B31193100BDA08D /* Project object */; 306 | } 307 | -------------------------------------------------------------------------------- /ElegantProgress.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ElegantProgress.xcodeproj/project.xcworkspace/xcshareddata/ElegantProgress.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 037724D1-2D49-4575-8F73-7D12098CAE59 9 | IDESourceControlProjectName 10 | project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | A9ADE021D0B7F7D1FE2313BB696D6E0734D878AF 14 | https://github.com/zhwayne/ElegantProgress.git 15 | 16 | IDESourceControlProjectPath 17 | ElegantProgress.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | A9ADE021D0B7F7D1FE2313BB696D6E0734D878AF 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/zhwayne/ElegantProgress.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | A9ADE021D0B7F7D1FE2313BB696D6E0734D878AF 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | A9ADE021D0B7F7D1FE2313BB696D6E0734D878AF 36 | IDESourceControlWCCName 37 | ElegantProgress 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ElegantProgress.xcodeproj/project.xcworkspace/xcuserdata/wayne.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhwayne/ElegantProgress/9701395c4d58cebfbdb922d021c066a68c2b2029/ElegantProgress.xcodeproj/project.xcworkspace/xcuserdata/wayne.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ElegantProgress.xcodeproj/xcuserdata/wayne.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /ElegantProgress.xcodeproj/xcuserdata/wayne.xcuserdatad/xcschemes/ElegantProgress.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ElegantProgress.xcodeproj/xcuserdata/wayne.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ElegantProgress.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B081FFAE1B31193100BDA08D 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ElegantProgress/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ElegantProgress 4 | // 5 | // Created by wayne on 15/6/17. 6 | // Copyright © 2015年 wayne. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | 20 | UIApplication.sharedApplication().statusBarHidden = false 21 | 22 | 23 | return true 24 | } 25 | 26 | func applicationWillResignActive(application: UIApplication) { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 29 | } 30 | 31 | func applicationDidEnterBackground(application: UIApplication) { 32 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 33 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 34 | } 35 | 36 | func applicationWillEnterForeground(application: UIApplication) { 37 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | func applicationDidBecomeActive(application: UIApplication) { 41 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 42 | } 43 | 44 | func applicationWillTerminate(application: UIApplication) { 45 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 46 | } 47 | 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /ElegantProgress/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /ElegantProgress/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /ElegantProgress/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ElegantProgress/ElegantProgressView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ElegantProgressView.swift 3 | // ElegantProgress 4 | // 5 | // Created by wayne on 15/6/17. 6 | // Copyright © 2015年 wayne. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ElegantProgressView: UIView { 12 | private var textLabel: UILabel! 13 | private var progressLayer: CAShapeLayer! 14 | 15 | var progress:CGFloat { 16 | get { return progressLayer.strokeEnd } 17 | set{ 18 | var realValue = newValue 19 | if realValue < CGFloat.min { 20 | realValue = CGFloat.min 21 | } 22 | 23 | CATransaction.begin() 24 | CATransaction.setDisableActions(false) 25 | CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)) 26 | CATransaction.setAnimationDuration(0.001) 27 | progressLayer.strokeEnd = realValue 28 | CATransaction.commit() 29 | 30 | if realValue <= CGFloat.min { 31 | textLabel.text = "Waiting..." 32 | } 33 | else if realValue == 1 { 34 | textLabel.text = "Done" 35 | } 36 | else { 37 | textLabel.text = NSString(format: "%.f%%", realValue * 100) as String 38 | } 39 | } 40 | } 41 | 42 | required init(coder aDecoder: NSCoder) { 43 | super.init(coder: aDecoder) 44 | } 45 | 46 | override init(frame: CGRect) { 47 | super.init(frame: frame) 48 | self.backgroundColor = UIColor.hexColor(0xeff8f3) 49 | 50 | /* 添加圆角 */ 51 | self.layer.masksToBounds = true 52 | self.layer.cornerRadius = self.bounds.width / 2 53 | 54 | // 添加 layers 55 | self.layoutSublayers() 56 | } 57 | 58 | private func layoutSublayers() { 59 | 60 | func addBottom() { // 给底盘添加黑色和白色的内阴影 61 | 62 | let topLeftShadowLayer = InnerShadowLayer() 63 | topLeftShadowLayer.frame = CGRectInset(self.bounds, -1.5, -1.5) 64 | topLeftShadowLayer.cornerRadius = topLeftShadowLayer.bounds.width / 2 65 | topLeftShadowLayer.innerShadowOpacity = 0.5 66 | topLeftShadowLayer.innerShadowRadius = 5 67 | topLeftShadowLayer.innerShadowOffset = CGSizeMake(1.6, 1.6) 68 | self.layer.addSublayer(topLeftShadowLayer) 69 | 70 | let bottomRightShadowLayer = InnerShadowLayer() 71 | bottomRightShadowLayer.frame = CGRectInset(self.bounds, -0.5, -0.5) 72 | bottomRightShadowLayer.cornerRadius = bottomRightShadowLayer.bounds.width / 2 73 | bottomRightShadowLayer.innerShadowColor = UIColor.whiteColor().CGColor 74 | bottomRightShadowLayer.innerShadowRadius = 1 75 | bottomRightShadowLayer.innerShadowOffset = CGSizeMake(-0.5, -0.5) 76 | self.layer.addSublayer(bottomRightShadowLayer) 77 | 78 | } 79 | addBottom() 80 | 81 | 82 | func addMiddle() { 83 | 84 | let middleRectInset = layer.bounds.width * 0.1 85 | 86 | let middleLayer = CAShapeLayer() 87 | middleLayer.frame = CGRectInset(layer.bounds, middleRectInset, middleRectInset) 88 | middleLayer.cornerRadius = middleLayer.bounds.width / 2 89 | middleLayer.backgroundColor = UIColor.clearColor().CGColor 90 | 91 | middleLayer.shouldRasterize = true 92 | middleLayer.contentsScale = UIScreen.mainScreen().scale 93 | middleLayer.rasterizationScale = UIScreen.mainScreen().scale 94 | middleLayer.shadowColor = UIColor.blackColor().CGColor 95 | middleLayer.shadowOffset = CGSizeMake(2, 6) // 注意比例 96 | middleLayer.shadowRadius = 5 97 | middleLayer.shadowOpacity = 0.3 98 | 99 | self.layer.addSublayer(middleLayer) 100 | 101 | /******************************************************************/ 102 | 103 | let gradientLayer = CAGradientLayer() 104 | gradientLayer.frame = CGRectInset(middleLayer.bounds, -0.2, -0.2) 105 | gradientLayer.cornerRadius = gradientLayer.bounds.width / 2 106 | gradientLayer.colors = [UIColor.hexColor(0xf8fdfa).CGColor, UIColor.hexColor(0xc1cbc6).CGColor] 107 | gradientLayer.locations = [-0.15, 0.75] 108 | gradientLayer.startPoint = CGPointMake(0.25, 0) 109 | gradientLayer.endPoint = CGPointMake(0.75, 1) 110 | middleLayer.addSublayer(gradientLayer) 111 | 112 | /******************************************************************/ 113 | 114 | let bottomRightShadowLayer = InnerShadowLayer() 115 | bottomRightShadowLayer.frame = CGRectInset(gradientLayer.bounds, -2, -2) 116 | bottomRightShadowLayer.cornerRadius = bottomRightShadowLayer.bounds.width / 2 117 | bottomRightShadowLayer.innerShadowOffset = CGSizeMake(-10, -10) 118 | bottomRightShadowLayer.innerShadowOpacity = 0.3 119 | bottomRightShadowLayer.innerShadowRadius = 18 120 | gradientLayer.masksToBounds = true 121 | gradientLayer.addSublayer(bottomRightShadowLayer) 122 | 123 | /******************************************************************/ 124 | 125 | let topLeftShadowLayer = InnerShadowLayer() 126 | topLeftShadowLayer.frame = CGRectInset(gradientLayer.bounds, -1, -1) 127 | topLeftShadowLayer.cornerRadius = topLeftShadowLayer.bounds.width / 2 128 | topLeftShadowLayer.innerShadowColor = UIColor.whiteColor().CGColor 129 | topLeftShadowLayer.innerShadowRadius = 1.5 130 | topLeftShadowLayer.innerShadowOffset = CGSizeMake(0.3, 0.9) 131 | gradientLayer.addSublayer(topLeftShadowLayer) 132 | 133 | } 134 | addMiddle() 135 | 136 | 137 | func addTop() { 138 | 139 | let topRectInset = layer.bounds.width * 0.25 140 | 141 | let topLayer = CAShapeLayer() 142 | topLayer.frame = CGRectInset(layer.bounds, topRectInset, topRectInset) 143 | topLayer.cornerRadius = topLayer.bounds.width / 2 144 | topLayer.backgroundColor = UIColor.hexColor(0xd5ddd9).CGColor 145 | topLayer.masksToBounds = true; 146 | 147 | self.layer.addSublayer(topLayer) 148 | 149 | /******************************************************************/ 150 | 151 | let bottomRightShadowLayer = InnerShadowLayer() 152 | bottomRightShadowLayer.frame = topLayer.bounds 153 | bottomRightShadowLayer.cornerRadius = bottomRightShadowLayer.bounds.width / 2 154 | bottomRightShadowLayer.innerShadowColor = UIColor.whiteColor().CGColor 155 | bottomRightShadowLayer.innerShadowOffset = CGSizeMake(-1, -1) 156 | bottomRightShadowLayer.innerShadowRadius = 2 157 | bottomRightShadowLayer.innerShadowOpacity = 0.6 158 | 159 | topLayer.addSublayer(bottomRightShadowLayer) 160 | 161 | /******************************************************************/ 162 | 163 | let topLeftShadowLayer = InnerShadowLayer() 164 | topLeftShadowLayer.frame = topLayer.bounds 165 | topLeftShadowLayer.cornerRadius = topLeftShadowLayer.bounds.width / 2 166 | topLeftShadowLayer.innerShadowRadius = 15 167 | topLeftShadowLayer.innerShadowOpacity = 0.2 168 | topLeftShadowLayer.innerShadowOffset = CGSizeMake(3, 9) 169 | 170 | topLayer.addSublayer(topLeftShadowLayer) 171 | 172 | } 173 | addTop() 174 | 175 | 176 | func addTextLabel() { 177 | 178 | let textRectInset = layer.bounds.width * 0.3 179 | let frame = CGRectInset(self.bounds, textRectInset, textRectInset) 180 | 181 | textLabel = UILabel(frame: frame) 182 | textLabel.text = "Waiting..." 183 | textLabel.font = UIFont(name: "HelveticaNeue-Thin", size: 32) 184 | textLabel.textColor = UIColor.hexColor(0x97aea6) 185 | textLabel.textAlignment = NSTextAlignment.Center 186 | textLabel.adjustsFontSizeToFitWidth = true 187 | self.addSubview(textLabel) 188 | 189 | } 190 | addTextLabel() 191 | 192 | 193 | func addProgress() { 194 | 195 | let gradientLayer = CAGradientLayer() 196 | gradientLayer.frame = layer.bounds 197 | gradientLayer.cornerRadius = gradientLayer.bounds.width / 2 198 | gradientLayer.colors = [UIColor.hexColor(0x70dc98).CGColor, UIColor.hexColor(0x70dcbf).CGColor] 199 | gradientLayer.locations = [0, 1] 200 | gradientLayer.startPoint = CGPointMake(0.25, 0) 201 | gradientLayer.endPoint = CGPointMake(0.75, 1) 202 | 203 | layer.insertSublayer(gradientLayer, atIndex: 0) 204 | 205 | 206 | let middleRectInset = layer.bounds.width * 0.1 207 | let path = UIBezierPath(arcCenter: layer.position, radius: (layer.bounds.width - middleRectInset) / 2, startAngle: CGFloat(angle: -90), endAngle: CGFloat(angle: 270), clockwise: true).CGPath 208 | 209 | progressLayer = CAShapeLayer() 210 | progressLayer.frame = CGRectInset(layer.bounds, layer.borderWidth, layer.borderWidth) 211 | progressLayer.fillColor = UIColor.clearColor().CGColor 212 | progressLayer.strokeColor = UIColor.hexColor(0x70dc98).CGColor 213 | progressLayer.opacity = 0.8 214 | progressLayer.lineCap = kCALineCapRound 215 | progressLayer.lineWidth = middleRectInset 216 | progressLayer.path = path 217 | progressLayer.strokeEnd = CGFloat.min 218 | 219 | gradientLayer.mask = progressLayer 220 | 221 | } 222 | addProgress() 223 | } 224 | } 225 | 226 | 227 | extension CGFloat { 228 | init(angle: CGFloat) { 229 | self = angle * CGFloat(M_PI) / 180.0 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /ElegantProgress/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIViewControllerBasedStatusBarAppearance 6 | 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 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 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationLandscapeLeft 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ElegantProgress/InnerShadowLayer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InnerShadowLayer.swift 3 | // InnerShadowLayer 4 | // 5 | // Created by wayne on 15/6/13. 6 | // Copyright © 2015年 wayne. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class InnerShadowLayer: CALayer { 12 | var innerShadowColor: CGColor? = UIColor.blackColor().CGColor { 13 | didSet { 14 | setNeedsDisplay() 15 | } 16 | } 17 | var innerShadowOffset: CGSize = CGSizeMake(0, 0) { 18 | didSet { 19 | setNeedsDisplay() 20 | } 21 | } 22 | var innerShadowRadius: CGFloat = 8 { 23 | didSet { 24 | setNeedsDisplay() 25 | } 26 | } 27 | var innerShadowOpacity: Float = 1 { 28 | didSet { 29 | setNeedsDisplay() 30 | } 31 | } 32 | 33 | required init?(coder aDecoder: NSCoder) { 34 | super.init(coder: aDecoder) 35 | } 36 | 37 | override init() { 38 | super.init() 39 | 40 | self.masksToBounds = true 41 | self.shouldRasterize = true 42 | self.contentsScale = UIScreen.mainScreen().scale 43 | self.rasterizationScale = UIScreen.mainScreen().scale 44 | 45 | setNeedsDisplay() 46 | } 47 | 48 | override func drawInContext(ctx: CGContext) { 49 | print("draw") 50 | // 设置 Context 属性 51 | // 允许抗锯齿 52 | CGContextSetAllowsAntialiasing(ctx, true); 53 | // 允许平滑 54 | CGContextSetShouldAntialias(ctx, true); 55 | // 设置插值质量 56 | CGContextSetInterpolationQuality(ctx, CGInterpolationQuality.High); 57 | 58 | // 以下为核心代码 59 | 60 | // 创建 color space 61 | let colorspace = CGColorSpaceCreateDeviceRGB(); 62 | 63 | var rect = self.bounds 64 | var radius = self.cornerRadius 65 | 66 | // 去除边框的大小 67 | if self.borderWidth != 0 { 68 | rect = CGRectInset(rect, self.borderWidth, self.borderWidth); 69 | radius -= self.borderWidth 70 | radius = max(radius, 0) 71 | } 72 | 73 | // 创建 inner shadow 的镂空路径 74 | let someInnerPath: CGPathRef = UIBezierPath(roundedRect: rect, cornerRadius: radius).CGPath 75 | CGContextAddPath(ctx, someInnerPath) 76 | CGContextClip(ctx) 77 | 78 | // 创建阴影填充区域,并镂空中心 79 | let shadowPath = CGPathCreateMutable() 80 | let shadowRect = CGRectInset(rect, -rect.size.width, -rect.size.width) 81 | CGPathAddRect(shadowPath, nil, shadowRect) 82 | CGPathAddPath(shadowPath, nil, someInnerPath); 83 | CGPathCloseSubpath(shadowPath) 84 | 85 | // 获取填充颜色信息 86 | let oldComponents: UnsafePointer = CGColorGetComponents(self.innerShadowColor) 87 | var newComponents:[CGFloat] = [0, 0, 0, 0] 88 | let numberOfComponents: Int = CGColorGetNumberOfComponents(self.innerShadowColor); 89 | switch (numberOfComponents){ 90 | case 2: 91 | // 灰度 92 | newComponents[0] = oldComponents[0] 93 | newComponents[1] = oldComponents[0] 94 | newComponents[2] = oldComponents[0] 95 | newComponents[3] = oldComponents[1] * CGFloat(self.innerShadowOpacity) 96 | case 4: 97 | // RGBA 98 | newComponents[0] = oldComponents[0] 99 | newComponents[1] = oldComponents[1] 100 | newComponents[2] = oldComponents[2] 101 | newComponents[3] = oldComponents[3] * CGFloat(self.innerShadowOpacity) 102 | default: break 103 | } 104 | 105 | // 根据颜色信息创建填充色 106 | let innerShadowColorWithMultipliedAlpha = CGColorCreate(colorspace, newComponents) 107 | 108 | // 填充阴影 109 | CGContextSetFillColorWithColor(ctx, innerShadowColorWithMultipliedAlpha) 110 | CGContextSetShadowWithColor(ctx, self.innerShadowOffset, self.innerShadowRadius, innerShadowColorWithMultipliedAlpha) 111 | CGContextAddPath(ctx, shadowPath) 112 | CGContextEOFillPath(ctx) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /ElegantProgress/UIColor+Ex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // a.swift 3 | // Book 4 | // 5 | // Created by wayne on 15/5/29. 6 | // Copyright (c) 2015年 wayne. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | extension UIColor { 13 | class func hexColor(color: Int) -> UIColor { 14 | let r = (CGFloat)((color & 0xFF0000) >> 16) / 255.0 15 | let g = (CGFloat)((color & 0xFF00) >> 8) / 255.0 16 | let b = (CGFloat)(color & 0xFF) / 255.0 17 | return UIColor(red: r, green: g, blue: b, alpha: 1) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ElegantProgress/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ElegantProgress 4 | // 5 | // Created by wayne on 15/6/17. 6 | // Copyright © 2015年 wayne. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | 13 | class ViewController: UIViewController { 14 | var progressView: ElegantProgressView! 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | let bounds = CGRectMake(0, 0, 260, 260) 20 | let center = CGPointMake(view.bounds.width / 2, view.bounds.height / 2) 21 | progressView = ElegantProgressView(frame: bounds) 22 | progressView.center = center 23 | 24 | self.view.addSubview(progressView) 25 | 26 | 27 | } 28 | 29 | override func touchesBegan(touches: Set, withEvent event: UIEvent?) { 30 | dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in 31 | for i in 0...100 { 32 | if i < 40 { 33 | NSThread.sleepForTimeInterval(0.03) 34 | } 35 | else if i < 60 { 36 | NSThread.sleepForTimeInterval(0.1) 37 | } 38 | else { 39 | NSThread.sleepForTimeInterval(0.01) 40 | } 41 | let progress = Double(i) / 100.0 42 | dispatch_sync(dispatch_get_main_queue(), { () -> Void in 43 | self.progressView.progress = CGFloat(progress) 44 | }) 45 | } 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ElegantProgress 2 | 3 | 一枚优雅的小清新拟物化进度条。 4 | 5 | Demo: 6 | 7 | 8 | ![](http://cdn.cocimg.com/bbs/attachment/postcate/topic/16/307402_189_d23014351328770370d40f6e531d8.gif) 9 | -------------------------------------------------------------------------------- /demo.m4v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhwayne/ElegantProgress/9701395c4d58cebfbdb922d021c066a68c2b2029/demo.m4v --------------------------------------------------------------------------------