├── .github └── FUNDING.yml ├── .gitignore ├── .swift-version ├── CHANGELOG.md ├── DemoApp ├── Podfile ├── Podfile.lock ├── SwiftSpinnerDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── SwiftSpinnerDemo │ ├── AppDelegate.swift │ ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── AppIcon-1024.0x1024.0@1x.png │ │ ├── AppIcon-20.0x20.0@1x.png │ │ ├── AppIcon-20.0x20.0@2x.png │ │ ├── AppIcon-20.0x20.0@3x.png │ │ ├── AppIcon-29.0x29.0@1x.png │ │ ├── AppIcon-29.0x29.0@2x.png │ │ ├── AppIcon-29.0x29.0@3x.png │ │ ├── AppIcon-40.0x40.0@1x.png │ │ ├── AppIcon-40.0x40.0@2x.png │ │ ├── AppIcon-40.0x40.0@3x.png │ │ ├── AppIcon-60.0x60.0@2x.png │ │ ├── AppIcon-60.0x60.0@3x.png │ │ ├── AppIcon-76.0x76.0@1x.png │ │ ├── AppIcon-76.0x76.0@2x.png │ │ ├── AppIcon-83.5x83.5@2x.png │ │ └── Contents.json │ ├── Contents.json │ ├── Hurricane_Irene.imageset │ │ ├── Contents.json │ │ └── Hurricane_Irene.jpg │ └── logo.imageset │ │ ├── Contents.json │ │ └── logo.pdf │ ├── Info.plist │ └── ViewController.swift ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── SwiftSpinner │ ├── Info-tvOS.plist │ ├── Info.plist │ ├── SwiftSpinner.h │ └── SwiftSpinner.swift ├── SwiftSpinner.podspec ├── SwiftSpinner.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── SwiftSpinner tvOS.xcscheme │ └── SwiftSpinner.xcscheme └── etc ├── Assets.sketch └── spinner-preview.gif /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: #[icanzilb] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.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 | .DS_Store 20 | 21 | # CocoaPods 22 | # 23 | # We recommend against adding the Pods directory to your .gitignore. However 24 | # you should judge for yourself, the pros and cons are mentioned at: 25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 26 | # 27 | # Pods/ 28 | DemoApp/Pods 29 | DemoApp/SwiftSpinnerDemo.xcworkspace 30 | SwiftSpinner.framework.zip 31 | 32 | # SwiftPM 33 | .swiftpm/ 34 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | `SwiftSpinner` adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | - `2.2.x` Releases - [2.2.0](#220) 6 | - `2.1.x` Releases - [2.1.0](#210) 7 | - `2.0.x` Releases - [2.0.0](#200) 8 | - `1.6.x` Releases - [1.6.0](#160) 9 | - `1.5.x` Releases - [1.5.0](#150) 10 | - `1.4.x` Releases - [1.4.0](#140) 11 | 12 | --- 13 | 14 | ## [2.2.0](https://github.com/icanzilb/SwiftSpinner/releases/tag/2.2.0) 15 | 16 | - Dropped iOS 8 compatibility 17 | 18 | ## [2.1.0](https://github.com/icanzilb/SwiftSpinner/releases/tag/2.1.0) 19 | 20 | - SwiftPM compatibility 21 | 22 | ## [2.0.0](https://github.com/icanzilb/SwiftSpinner/releases/tag/2.0.0) 23 | 24 | ### Breaking change 25 | 26 | The singleton property has been renamed to `shared` in accordance with other platform conventions. 27 | 28 | ### Other changes 29 | 30 | - Added a completion handler to the `hdie` method, see #135 31 | - Merged #136 32 | - Merged #134 33 | 34 | ## [1.6.0](https://github.com/icanzilb/SwiftSpinner/releases/tag/1.6.0) 35 | 36 | - Support Swift 4.2 37 | - Merge #122 38 | - Merge #127 39 | 40 | ## [1.5.0](https://github.com/icanzilb/SwiftSpinner/releases/tag/1.5.0) 41 | 42 | - hierarchy edge case fix 43 | - add more color customization options 44 | 45 | ## [1.4.0](https://github.com/icanzilb/SwiftSpinner/releases/tag/1.4.0) 46 | 47 | - Support Swift 4 48 | -------------------------------------------------------------------------------- /DemoApp/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | platform :ios, '8.0' 3 | use_frameworks! 4 | 5 | target 'SwiftSpinnerDemo' do 6 | pod "SwiftSpinner", :path => ".." 7 | end 8 | -------------------------------------------------------------------------------- /DemoApp/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SwiftSpinner (2.2.0) 3 | 4 | DEPENDENCIES: 5 | - SwiftSpinner (from `..`) 6 | 7 | EXTERNAL SOURCES: 8 | SwiftSpinner: 9 | :path: ".." 10 | 11 | SPEC CHECKSUMS: 12 | SwiftSpinner: f082e7783f7ea6c75dad6c8d9e781fbd0e1bdbd9 13 | 14 | PODFILE CHECKSUM: 5adf66974bfcbc3d3779f9ca34933795856ca3dc 15 | 16 | COCOAPODS: 1.10.0 17 | -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8214CD3F7EBE60FDA5D144D7 /* Pods_SwiftSpinnerDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62FB9D7DED93CCAF58068570 /* Pods_SwiftSpinnerDemo.framework */; }; 11 | 9C6D4F131A6BFE8500B10961 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6D4F121A6BFE8500B10961 /* AppDelegate.swift */; }; 12 | 9C6D4F151A6BFE8500B10961 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6D4F141A6BFE8500B10961 /* ViewController.swift */; }; 13 | 9C6D4F181A6BFE8500B10961 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9C6D4F161A6BFE8500B10961 /* Main.storyboard */; }; 14 | 9C6D4F1A1A6BFE8500B10961 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9C6D4F191A6BFE8500B10961 /* Images.xcassets */; }; 15 | 9C6D4F1D1A6BFE8500B10961 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9C6D4F1B1A6BFE8500B10961 /* LaunchScreen.xib */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 21415BA7C8806F30C948C592 /* Pods-SwiftSpinnerDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSpinnerDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSpinnerDemo/Pods-SwiftSpinnerDemo.release.xcconfig"; sourceTree = ""; }; 20 | 62FB9D7DED93CCAF58068570 /* Pods_SwiftSpinnerDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftSpinnerDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 8612604C661B52F9AAEF005F /* Pods-SwiftSpinnerDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSpinnerDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSpinnerDemo/Pods-SwiftSpinnerDemo.debug.xcconfig"; sourceTree = ""; }; 22 | 9C6D4F0D1A6BFE8500B10961 /* SwiftSpinnerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftSpinnerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 9C6D4F111A6BFE8500B10961 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 24 | 9C6D4F121A6BFE8500B10961 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 25 | 9C6D4F141A6BFE8500B10961 /* ViewController.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; tabWidth = 4; }; 26 | 9C6D4F171A6BFE8500B10961 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 27 | 9C6D4F191A6BFE8500B10961 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 28 | 9C6D4F1C1A6BFE8500B10961 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 9C6D4F0A1A6BFE8500B10961 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | 8214CD3F7EBE60FDA5D144D7 /* Pods_SwiftSpinnerDemo.framework in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 1BF1807D69DAFE8395B13A82 /* Pods */ = { 44 | isa = PBXGroup; 45 | children = ( 46 | 8612604C661B52F9AAEF005F /* Pods-SwiftSpinnerDemo.debug.xcconfig */, 47 | 21415BA7C8806F30C948C592 /* Pods-SwiftSpinnerDemo.release.xcconfig */, 48 | ); 49 | name = Pods; 50 | sourceTree = ""; 51 | }; 52 | 9C6AC1CC9B704EC21CC3D44F /* Frameworks */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 62FB9D7DED93CCAF58068570 /* Pods_SwiftSpinnerDemo.framework */, 56 | ); 57 | name = Frameworks; 58 | sourceTree = ""; 59 | }; 60 | 9C6D4F041A6BFE8500B10961 = { 61 | isa = PBXGroup; 62 | children = ( 63 | 9C6D4F0F1A6BFE8500B10961 /* SwiftSpinnerDemo */, 64 | 9C6D4F0E1A6BFE8500B10961 /* Products */, 65 | 1BF1807D69DAFE8395B13A82 /* Pods */, 66 | 9C6AC1CC9B704EC21CC3D44F /* Frameworks */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | 9C6D4F0E1A6BFE8500B10961 /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 9C6D4F0D1A6BFE8500B10961 /* SwiftSpinnerDemo.app */, 74 | ); 75 | name = Products; 76 | sourceTree = ""; 77 | }; 78 | 9C6D4F0F1A6BFE8500B10961 /* SwiftSpinnerDemo */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 9C6D4F121A6BFE8500B10961 /* AppDelegate.swift */, 82 | 9C6D4F141A6BFE8500B10961 /* ViewController.swift */, 83 | 9C6D4F161A6BFE8500B10961 /* Main.storyboard */, 84 | 9C6D4F191A6BFE8500B10961 /* Images.xcassets */, 85 | 9C6D4F1B1A6BFE8500B10961 /* LaunchScreen.xib */, 86 | 9C6D4F101A6BFE8500B10961 /* Supporting Files */, 87 | ); 88 | path = SwiftSpinnerDemo; 89 | sourceTree = ""; 90 | }; 91 | 9C6D4F101A6BFE8500B10961 /* Supporting Files */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 9C6D4F111A6BFE8500B10961 /* Info.plist */, 95 | ); 96 | name = "Supporting Files"; 97 | sourceTree = ""; 98 | }; 99 | /* End PBXGroup section */ 100 | 101 | /* Begin PBXNativeTarget section */ 102 | 9C6D4F0C1A6BFE8500B10961 /* SwiftSpinnerDemo */ = { 103 | isa = PBXNativeTarget; 104 | buildConfigurationList = 9C6D4F2C1A6BFE8500B10961 /* Build configuration list for PBXNativeTarget "SwiftSpinnerDemo" */; 105 | buildPhases = ( 106 | B8923B58542177DAC45C73FB /* [CP] Check Pods Manifest.lock */, 107 | 9C6D4F091A6BFE8500B10961 /* Sources */, 108 | 9C6D4F0A1A6BFE8500B10961 /* Frameworks */, 109 | 9C6D4F0B1A6BFE8500B10961 /* Resources */, 110 | 6406E8FDEE4C37FC448E1983 /* [CP] Embed Pods Frameworks */, 111 | ); 112 | buildRules = ( 113 | ); 114 | dependencies = ( 115 | ); 116 | name = SwiftSpinnerDemo; 117 | productName = SwiftSpinnerDemo; 118 | productReference = 9C6D4F0D1A6BFE8500B10961 /* SwiftSpinnerDemo.app */; 119 | productType = "com.apple.product-type.application"; 120 | }; 121 | /* End PBXNativeTarget section */ 122 | 123 | /* Begin PBXProject section */ 124 | 9C6D4F051A6BFE8500B10961 /* Project object */ = { 125 | isa = PBXProject; 126 | attributes = { 127 | LastSwiftMigration = 0700; 128 | LastSwiftUpdateCheck = 0700; 129 | LastUpgradeCheck = 1020; 130 | ORGANIZATIONNAME = "Underplot ltd."; 131 | TargetAttributes = { 132 | 9C6D4F0C1A6BFE8500B10961 = { 133 | CreatedOnToolsVersion = 6.2; 134 | DevelopmentTeam = H72GR44F4M; 135 | LastSwiftMigration = 1020; 136 | ProvisioningStyle = Manual; 137 | }; 138 | }; 139 | }; 140 | buildConfigurationList = 9C6D4F081A6BFE8500B10961 /* Build configuration list for PBXProject "SwiftSpinnerDemo" */; 141 | compatibilityVersion = "Xcode 3.2"; 142 | developmentRegion = en; 143 | hasScannedForEncodings = 0; 144 | knownRegions = ( 145 | en, 146 | Base, 147 | ); 148 | mainGroup = 9C6D4F041A6BFE8500B10961; 149 | productRefGroup = 9C6D4F0E1A6BFE8500B10961 /* Products */; 150 | projectDirPath = ""; 151 | projectRoot = ""; 152 | targets = ( 153 | 9C6D4F0C1A6BFE8500B10961 /* SwiftSpinnerDemo */, 154 | ); 155 | }; 156 | /* End PBXProject section */ 157 | 158 | /* Begin PBXResourcesBuildPhase section */ 159 | 9C6D4F0B1A6BFE8500B10961 /* Resources */ = { 160 | isa = PBXResourcesBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | 9C6D4F181A6BFE8500B10961 /* Main.storyboard in Resources */, 164 | 9C6D4F1D1A6BFE8500B10961 /* LaunchScreen.xib in Resources */, 165 | 9C6D4F1A1A6BFE8500B10961 /* Images.xcassets in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 6406E8FDEE4C37FC448E1983 /* [CP] Embed Pods Frameworks */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | "${PODS_ROOT}/Target Support Files/Pods-SwiftSpinnerDemo/Pods-SwiftSpinnerDemo-frameworks.sh", 179 | "${BUILT_PRODUCTS_DIR}/SwiftSpinner/SwiftSpinner.framework", 180 | ); 181 | name = "[CP] Embed Pods Frameworks"; 182 | outputPaths = ( 183 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftSpinner.framework", 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | shellPath = /bin/sh; 187 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SwiftSpinnerDemo/Pods-SwiftSpinnerDemo-frameworks.sh\"\n"; 188 | showEnvVarsInLog = 0; 189 | }; 190 | B8923B58542177DAC45C73FB /* [CP] Check Pods Manifest.lock */ = { 191 | isa = PBXShellScriptBuildPhase; 192 | buildActionMask = 2147483647; 193 | files = ( 194 | ); 195 | inputFileListPaths = ( 196 | ); 197 | inputPaths = ( 198 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 199 | "${PODS_ROOT}/Manifest.lock", 200 | ); 201 | name = "[CP] Check Pods Manifest.lock"; 202 | outputFileListPaths = ( 203 | ); 204 | outputPaths = ( 205 | "$(DERIVED_FILE_DIR)/Pods-SwiftSpinnerDemo-checkManifestLockResult.txt", 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | shellPath = /bin/sh; 209 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 210 | showEnvVarsInLog = 0; 211 | }; 212 | /* End PBXShellScriptBuildPhase section */ 213 | 214 | /* Begin PBXSourcesBuildPhase section */ 215 | 9C6D4F091A6BFE8500B10961 /* Sources */ = { 216 | isa = PBXSourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | 9C6D4F151A6BFE8500B10961 /* ViewController.swift in Sources */, 220 | 9C6D4F131A6BFE8500B10961 /* AppDelegate.swift in Sources */, 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | /* End PBXSourcesBuildPhase section */ 225 | 226 | /* Begin PBXVariantGroup section */ 227 | 9C6D4F161A6BFE8500B10961 /* Main.storyboard */ = { 228 | isa = PBXVariantGroup; 229 | children = ( 230 | 9C6D4F171A6BFE8500B10961 /* Base */, 231 | ); 232 | name = Main.storyboard; 233 | sourceTree = ""; 234 | }; 235 | 9C6D4F1B1A6BFE8500B10961 /* LaunchScreen.xib */ = { 236 | isa = PBXVariantGroup; 237 | children = ( 238 | 9C6D4F1C1A6BFE8500B10961 /* Base */, 239 | ); 240 | name = LaunchScreen.xib; 241 | sourceTree = ""; 242 | }; 243 | /* End PBXVariantGroup section */ 244 | 245 | /* Begin XCBuildConfiguration section */ 246 | 9C6D4F2A1A6BFE8500B10961 /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALWAYS_SEARCH_USER_PATHS = NO; 250 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 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_BLOCK_CAPTURE_AUTORELEASING = YES; 256 | CLANG_WARN_BOOL_CONVERSION = YES; 257 | CLANG_WARN_COMMA = YES; 258 | CLANG_WARN_CONSTANT_CONVERSION = YES; 259 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 260 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 261 | CLANG_WARN_EMPTY_BODY = YES; 262 | CLANG_WARN_ENUM_CONVERSION = YES; 263 | CLANG_WARN_INFINITE_RECURSION = YES; 264 | CLANG_WARN_INT_CONVERSION = YES; 265 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 266 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 267 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 268 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 269 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 270 | CLANG_WARN_STRICT_PROTOTYPES = YES; 271 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 272 | CLANG_WARN_UNREACHABLE_CODE = YES; 273 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 274 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 275 | COPY_PHASE_STRIP = NO; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | ENABLE_TESTABILITY = YES; 278 | GCC_C_LANGUAGE_STANDARD = gnu99; 279 | GCC_DYNAMIC_NO_PIC = NO; 280 | GCC_NO_COMMON_BLOCKS = YES; 281 | GCC_OPTIMIZATION_LEVEL = 0; 282 | GCC_PREPROCESSOR_DEFINITIONS = ( 283 | "DEBUG=1", 284 | "$(inherited)", 285 | ); 286 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 287 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 288 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 289 | GCC_WARN_UNDECLARED_SELECTOR = YES; 290 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 291 | GCC_WARN_UNUSED_FUNCTION = YES; 292 | GCC_WARN_UNUSED_VARIABLE = YES; 293 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 294 | MTL_ENABLE_DEBUG_INFO = YES; 295 | ONLY_ACTIVE_ARCH = YES; 296 | SDKROOT = iphoneos; 297 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 298 | }; 299 | name = Debug; 300 | }; 301 | 9C6D4F2B1A6BFE8500B10961 /* Release */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ALWAYS_SEARCH_USER_PATHS = NO; 305 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 306 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 307 | CLANG_CXX_LIBRARY = "libc++"; 308 | CLANG_ENABLE_MODULES = YES; 309 | CLANG_ENABLE_OBJC_ARC = YES; 310 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 311 | CLANG_WARN_BOOL_CONVERSION = YES; 312 | CLANG_WARN_COMMA = YES; 313 | CLANG_WARN_CONSTANT_CONVERSION = YES; 314 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 315 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 325 | CLANG_WARN_STRICT_PROTOTYPES = YES; 326 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 327 | CLANG_WARN_UNREACHABLE_CODE = YES; 328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 329 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 330 | COPY_PHASE_STRIP = NO; 331 | ENABLE_NS_ASSERTIONS = NO; 332 | ENABLE_STRICT_OBJC_MSGSEND = YES; 333 | GCC_C_LANGUAGE_STANDARD = gnu99; 334 | GCC_NO_COMMON_BLOCKS = YES; 335 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 336 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 337 | GCC_WARN_UNDECLARED_SELECTOR = YES; 338 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 339 | GCC_WARN_UNUSED_FUNCTION = YES; 340 | GCC_WARN_UNUSED_VARIABLE = YES; 341 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 342 | MTL_ENABLE_DEBUG_INFO = NO; 343 | SDKROOT = iphoneos; 344 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 345 | VALIDATE_PRODUCT = YES; 346 | }; 347 | name = Release; 348 | }; 349 | 9C6D4F2D1A6BFE8500B10961 /* Debug */ = { 350 | isa = XCBuildConfiguration; 351 | baseConfigurationReference = 8612604C661B52F9AAEF005F /* Pods-SwiftSpinnerDemo.debug.xcconfig */; 352 | buildSettings = { 353 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 354 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 355 | CODE_SIGN_STYLE = Manual; 356 | DEVELOPMENT_TEAM = H72GR44F4M; 357 | INFOPLIST_FILE = SwiftSpinnerDemo/Info.plist; 358 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 359 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 360 | PRODUCT_BUNDLE_IDENTIFIER = "com.underplot.$(PRODUCT_NAME:rfc1034identifier)"; 361 | PRODUCT_NAME = "$(TARGET_NAME)"; 362 | PROVISIONING_PROFILE = "f7168a28-8f3d-4e45-bcbd-a54a870789e7"; 363 | PROVISIONING_PROFILE_SPECIFIER = Development; 364 | SWIFT_COMPILATION_MODE = wholemodule; 365 | SWIFT_VERSION = 5.0; 366 | TARGETED_DEVICE_FAMILY = "1,2"; 367 | }; 368 | name = Debug; 369 | }; 370 | 9C6D4F2E1A6BFE8500B10961 /* Release */ = { 371 | isa = XCBuildConfiguration; 372 | baseConfigurationReference = 21415BA7C8806F30C948C592 /* Pods-SwiftSpinnerDemo.release.xcconfig */; 373 | buildSettings = { 374 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | CODE_SIGN_STYLE = Manual; 377 | DEVELOPMENT_TEAM = H72GR44F4M; 378 | INFOPLIST_FILE = SwiftSpinnerDemo/Info.plist; 379 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 380 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 381 | PRODUCT_BUNDLE_IDENTIFIER = "com.underplot.$(PRODUCT_NAME:rfc1034identifier)"; 382 | PRODUCT_NAME = "$(TARGET_NAME)"; 383 | PROVISIONING_PROFILE = "f7168a28-8f3d-4e45-bcbd-a54a870789e7"; 384 | PROVISIONING_PROFILE_SPECIFIER = Development; 385 | SWIFT_VERSION = 5.0; 386 | TARGETED_DEVICE_FAMILY = "1,2"; 387 | }; 388 | name = Release; 389 | }; 390 | /* End XCBuildConfiguration section */ 391 | 392 | /* Begin XCConfigurationList section */ 393 | 9C6D4F081A6BFE8500B10961 /* Build configuration list for PBXProject "SwiftSpinnerDemo" */ = { 394 | isa = XCConfigurationList; 395 | buildConfigurations = ( 396 | 9C6D4F2A1A6BFE8500B10961 /* Debug */, 397 | 9C6D4F2B1A6BFE8500B10961 /* Release */, 398 | ); 399 | defaultConfigurationIsVisible = 0; 400 | defaultConfigurationName = Release; 401 | }; 402 | 9C6D4F2C1A6BFE8500B10961 /* Build configuration list for PBXNativeTarget "SwiftSpinnerDemo" */ = { 403 | isa = XCConfigurationList; 404 | buildConfigurations = ( 405 | 9C6D4F2D1A6BFE8500B10961 /* Debug */, 406 | 9C6D4F2E1A6BFE8500B10961 /* Release */, 407 | ); 408 | defaultConfigurationIsVisible = 0; 409 | defaultConfigurationName = Release; 410 | }; 411 | /* End XCConfigurationList section */ 412 | }; 413 | rootObject = 9C6D4F051A6BFE8500B10961 /* Project object */; 414 | } 415 | -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 Marin Todorov, Underplot ltd. 3 | // This code is distributed under the terms and conditions of the MIT license. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | // 9 | 10 | import UIKit 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-1024.0x1024.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-1024.0x1024.0@1x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@1x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@2x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@3x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@1x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@2x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@3x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@1x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@2x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@3x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-60.0x60.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-60.0x60.0@2x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-60.0x60.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-60.0x60.0@3x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-76.0x76.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-76.0x76.0@1x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-76.0x76.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-76.0x76.0@2x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "appicon", 4 | "version" : 1 5 | }, 6 | "images" : [ 7 | { 8 | "size" : "20x20", 9 | "filename" : "AppIcon-20.0x20.0@2x.png", 10 | "idiom" : "iphone", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "size" : "20x20", 15 | "filename" : "AppIcon-20.0x20.0@3x.png", 16 | "idiom" : "iphone", 17 | "scale" : "3x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "filename" : "AppIcon-29.0x29.0@2x.png", 22 | "idiom" : "iphone", 23 | "scale" : "2x" 24 | }, 25 | { 26 | "size" : "29x29", 27 | "filename" : "AppIcon-29.0x29.0@3x.png", 28 | "idiom" : "iphone", 29 | "scale" : "3x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "filename" : "AppIcon-40.0x40.0@2x.png", 34 | "idiom" : "iphone", 35 | "scale" : "2x" 36 | }, 37 | { 38 | "size" : "40x40", 39 | "filename" : "AppIcon-40.0x40.0@3x.png", 40 | "idiom" : "iphone", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "size" : "60x60", 45 | "filename" : "AppIcon-60.0x60.0@2x.png", 46 | "idiom" : "iphone", 47 | "scale" : "2x" 48 | }, 49 | { 50 | "size" : "60x60", 51 | "filename" : "AppIcon-60.0x60.0@3x.png", 52 | "idiom" : "iphone", 53 | "scale" : "3x" 54 | }, 55 | { 56 | "size" : "20x20", 57 | "filename" : "AppIcon-20.0x20.0@1x.png", 58 | "idiom" : "ipad", 59 | "scale" : "1x" 60 | }, 61 | { 62 | "size" : "20x20", 63 | "filename" : "AppIcon-20.0x20.0@2x.png", 64 | "idiom" : "ipad", 65 | "scale" : "2x" 66 | }, 67 | { 68 | "size" : "29x29", 69 | "filename" : "AppIcon-29.0x29.0@1x.png", 70 | "idiom" : "ipad", 71 | "scale" : "1x" 72 | }, 73 | { 74 | "size" : "29x29", 75 | "filename" : "AppIcon-29.0x29.0@2x.png", 76 | "idiom" : "ipad", 77 | "scale" : "2x" 78 | }, 79 | { 80 | "size" : "40x40", 81 | "filename" : "AppIcon-40.0x40.0@1x.png", 82 | "idiom" : "ipad", 83 | "scale" : "1x" 84 | }, 85 | { 86 | "size" : "40x40", 87 | "filename" : "AppIcon-40.0x40.0@2x.png", 88 | "idiom" : "ipad", 89 | "scale" : "2x" 90 | }, 91 | { 92 | "size" : "76x76", 93 | "filename" : "AppIcon-76.0x76.0@1x.png", 94 | "idiom" : "ipad", 95 | "scale" : "1x" 96 | }, 97 | { 98 | "size" : "76x76", 99 | "filename" : "AppIcon-76.0x76.0@2x.png", 100 | "idiom" : "ipad", 101 | "scale" : "2x" 102 | }, 103 | { 104 | "size" : "83.5x83.5", 105 | "filename" : "AppIcon-83.5x83.5@2x.png", 106 | "idiom" : "ipad", 107 | "scale" : "2x" 108 | }, 109 | { 110 | "size" : "1024x1024", 111 | "filename" : "AppIcon-1024.0x1024.0@1x.png", 112 | "idiom" : "ios-marketing", 113 | "scale" : "1x" 114 | } 115 | ] 116 | } -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/Hurricane_Irene.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "Hurricane_Irene.jpg" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/Hurricane_Irene.imageset/Hurricane_Irene.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/Hurricane_Irene.imageset/Hurricane_Irene.jpg -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "logo.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Images.xcassets/logo.imageset/logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/DemoApp/SwiftSpinnerDemo/Images.xcassets/logo.imageset/logo.pdf -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | UIInterfaceOrientationPortraitUpsideDown 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /DemoApp/SwiftSpinnerDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015-present Marin Todorov, Underplot ltd. 3 | // This code is distributed under the terms and conditions of the MIT license. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | // 9 | 10 | import UIKit 11 | import SwiftSpinner 12 | 13 | class ViewController: UIViewController { 14 | 15 | @IBOutlet var labelContainerView: UIView! 16 | var progress = 0.0 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | labelContainerView.transform = CGAffineTransform(translationX: 0, y: 200) 21 | } 22 | 23 | func delay(seconds: Double, completion: @escaping () -> ()) { 24 | let popTime = DispatchTime.now() + Double(Int64( Double(NSEC_PER_SEC) * seconds )) / Double(NSEC_PER_SEC) 25 | 26 | DispatchQueue.main.asyncAfter(deadline: popTime) { 27 | completion() 28 | } 29 | } 30 | 31 | override func viewWillAppear(_ animated: Bool) { 32 | super.viewWillAppear(animated) 33 | 34 | self.demoSpinner() 35 | } 36 | 37 | func demoSpinner() { 38 | UIView.animate(withDuration: 0.5) { 39 | self.labelContainerView.transform = .identity 40 | } 41 | 42 | SwiftSpinner.show(delay: 0.5, title: "Shouldn't see this one", animated: true) 43 | SwiftSpinner.hide() 44 | 45 | SwiftSpinner.show(delay: 1.0, title: "Connecting...", animated: true) 46 | 47 | delay(seconds: 2.0, completion: { 48 | SwiftSpinner.show("Connecting \nto satellite...").addTapHandler({ 49 | print("tapped") 50 | SwiftSpinner.hide() 51 | }, subtitle: "Tap to hide while connecting! This will affect only the current operation.") 52 | }) 53 | 54 | delay(seconds: 6.0, completion: { 55 | SwiftSpinner.show("Authenticating user account") 56 | }) 57 | 58 | delay(seconds: 10.0, completion: { 59 | SwiftSpinner.shared.outerColor = UIColor.red.withAlphaComponent(0.5) 60 | SwiftSpinner.setTitleColor(UIColor.red) 61 | SwiftSpinner.show("Failed to connect, waiting...", animated: false) 62 | }) 63 | 64 | delay(seconds: 14.0, completion: { 65 | SwiftSpinner.shared.outerColor = nil 66 | SwiftSpinner.setTitleFont(UIFont(name: "Futura", size: 22.0)) 67 | SwiftSpinner.setTitleColor(UIColor.white) 68 | SwiftSpinner.show("Retrying to authenticate") 69 | }) 70 | 71 | delay(seconds: 18.0, completion: { 72 | SwiftSpinner.setTitleColor(UIColor.green) 73 | SwiftSpinner.show("Connecting...") 74 | }) 75 | 76 | delay(seconds: 21.0, completion: { 77 | SwiftSpinner.setTitleFont(nil) 78 | SwiftSpinner.shared.innerColor = UIColor.green.withAlphaComponent(0.5) 79 | SwiftSpinner.show(duration: 2.0, title: "Connected", animated: false) 80 | }) 81 | 82 | delay(seconds: 24.0) { 83 | SwiftSpinner.setTitleColor(UIColor.white) 84 | SwiftSpinner.shared.innerColor = nil 85 | Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.timerFire), userInfo: nil, repeats: true) 86 | } 87 | 88 | delay(seconds: 34.0, completion: { 89 | self.demoSpinner() 90 | }) 91 | } 92 | 93 | @objc func timerFire(_ timer: Timer) { 94 | progress += (timer.timeInterval/5) 95 | SwiftSpinner.show(progress: progress, title: "Downloading: \(Int(progress * 100))% completed") 96 | if progress >= 1 { 97 | progress = 0 98 | timer.invalidate() 99 | SwiftSpinner.show(duration: 2.0, title: "Complete!", animated: false) 100 | } 101 | } 102 | 103 | override var preferredStatusBarStyle: UIStatusBarStyle { 104 | return .lightContent 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Marin Todorov 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 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SwiftSpinner", 8 | platforms: [.iOS(.v9), .tvOS(.v9)], 9 | products: [ 10 | .library(name: "SwiftSpinner", targets: ["SwiftSpinner"]) 11 | ], 12 | targets: [ 13 | .target(name: "SwiftSpinner") 14 | ] 15 | ) 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftSpinner 2 | 3 | [![Version](https://img.shields.io/cocoapods/v/SwiftSpinner.svg?style=flat)](http://cocoadocs.org/docsets/SwiftSpinner) 4 | [![License](https://img.shields.io/cocoapods/l/SwiftSpinner.svg?style=flat)](http://cocoadocs.org/docsets/SwiftSpinner) 5 | [![Platform](https://img.shields.io/cocoapods/p/SwiftSpinner.svg?style=flat)](http://cocoadocs.org/docsets/SwiftSpinner) 6 | ![Swift 5.0](https://img.shields.io/badge/swift-5.0-orange.svg) 7 | 8 | SwiftSpinner is an extra beautiful activity indicator with plain and bold style. It uses dynamic blur and translucency to overlay the current screen contents and display an activity indicator with text (or the so called “spinner”). 9 | 10 | - - - 11 | 12 | I developed it for my Swift app called **Doodle Doodle** and wanted to share it with everyone. 13 | 14 | This is how the activity looks like (from the demo app): 15 | 16 | ![SwiftSpinner Screenshot](https://raw.githubusercontent.com/icanzilb/SwiftSpinner/main/etc/spinner-preview.gif) 17 | 18 | ## Usage 19 | 20 | To run the example project, clone the repo, and run `pod install` from the DemoApp directory first. That’ll run the demo program which shows you how the spinner looks like and what it can do. 21 | 22 | #### Code samples 23 | 24 | The simple code to get `SwiftSpinner` running in your own app. 25 | 26 | * In case you installed SwiftSpinner via CocoaPods you need to import it (add this somewhere at the top of your source code file): 27 | 28 | ```swift 29 | import SwiftSpinner 30 | ``` 31 | 32 | * When you want to show an animated activity (eg. rings are randomly rotating around): 33 | 34 | ```swift 35 | SwiftSpinner.show("Connecting to satellite...") 36 | ``` 37 | 38 | * If you want to show a static activity indicator (eg. a message with two complete rings around it) 39 | 40 | ```swift 41 | SwiftSpinner.show("Failed to connect, waiting...", animated: false) 42 | ``` 43 | 44 | * When you want to hide the activity: 45 | 46 | ```swift 47 | SwiftSpinner.hide() 48 | ``` 49 | 50 | In case you want to do something after the hiding animation completes you can provide a closure to the `hide()` method: 51 | 52 | ```swift 53 | SwiftSpinner.hide({ 54 | //do stuff 55 | }) 56 | ``` 57 | 58 | 59 | That's all. If you want to change the text of the current activity, just call `show(...)` again, this will animate the old text into the new text. 60 | 61 | ## Beyond the basics 62 | 63 | If you are using `SwiftSpinner` to show an alert message you can also easily add a dismiss handler: 64 | 65 | ```swift 66 | SwiftSpinner.show("Connecting \nto satellite...").addTapHandler({ 67 | SwiftSpinner.hide() 68 | }) 69 | ``` 70 | 71 | Or even add a subtitle to let the user know they can tap to do stuff: 72 | 73 | ```swift 74 | SwiftSpinner.show("Connecting \nto satellite...").addTapHandler({ 75 | SwiftSpinner.hide() 76 | }, subtitle: "Tap to hide while connecting! This will affect only the current operation.") 77 | ``` 78 | 79 | In case you want to adjust the font of the spinner title: 80 | 81 | ```swift 82 | SwiftSpinner.setTitleFont(UIFont(name: "Futura", size: 22.0)) 83 | ``` 84 | 85 | To reset back to the default font: 86 | 87 | ```swift 88 | SwiftSpinner.setTitleFont(nil) 89 | ``` 90 | 91 | In case you want to change an arbitrary aspect of the text on screen access directly: 92 | 93 | ```swift 94 | SwiftSpinner.shared.titleLabel 95 | SwiftSpinner.shared.subtitleLabel 96 | ``` 97 | 98 | You can show a spinner only if certain amount of time has passed (e.g. if you are downloading a file - show a message only if the operation takes longer than certain amount of time): 99 | 100 | ```swift 101 | SwiftSpinner.show(delay: 2.0, title: "It's taking longer than expected") 102 | ``` 103 | 104 | If you call `show(…)` or `hide()` before the `delay` time has passed - this will clear the call to `show(delay: …)`. 105 | 106 | You show a message for a certain duration: 107 | ```swift 108 | SwiftSpinner.show(duration: 4.0, title: "It's taking longer than expected") 109 | ``` 110 | 111 | Or you can use `SwiftSpinner` as a progress bar by directly setting the current progress like so: 112 | 113 | ```swift 114 | SwiftSpinner.show(progress: 0.2, title: "Downloading Data...") // 20% trough the process 115 | ``` 116 | 117 | If you want to see the content behind the spinner, set the showBlurBackground to false: 118 | ```swift 119 | SwiftSpinner.showBlurBackground = false 120 | ``` 121 | 122 | ## Requirements 123 | 124 | UIKit must be imported. If you are using SwiftSpinner in an App Extension, you must add `EXTENSION` to your `Other Swift Flags` Build Settings. 125 | 126 | ![Extension Setting Screenshot](https://user-images.githubusercontent.com/444725/26855417-a7a8241a-4acf-11e7-8528-b37a28448113.png) 127 | 128 | ## Installation 129 | 130 | `SwiftSpinner` is available through [CocoaPods](http://cocoapods.org). To install 131 | it, simply add the following line to your `Podfile`: 132 | 133 | ``` 134 | pod "SwiftSpinner" 135 | ``` 136 | 137 | In case you don’t want to use CocoaPods - just copy the file **SwiftSpinner/SwiftSpinner.swift** to your Xcode project. 138 | 139 | Credit 140 | ======== 141 | 142 | Author: **Marin Todorov** 143 | 144 | * [http://www.underplot.com](http://www.underplot.com) 145 | * [https://twitter.com/icanzilb](https://twitter.com/icanzilb) 146 | 147 | More about Marin: 148 | 149 | 150 | 151 | 155 | 159 | 160 |
152 |
153 | iOS Animations by Tutorials, Author
154 |
156 |
157 | iOS Animations by Emails Newsletter, Author
158 |
161 | 162 | ## License 163 | 164 | `SwiftSpinner` is available under the MIT license. See the LICENSE file for more info. 165 | -------------------------------------------------------------------------------- /Sources/SwiftSpinner/Info-tvOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.8.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Sources/SwiftSpinner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.8.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Sources/SwiftSpinner/SwiftSpinner.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftSpinner.h 3 | // SwiftSpinner 4 | // 5 | // Created by Doug Woodgate (GE) on 2/19/16. 6 | // Copyright © 2016 Dwoodgate. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SwiftSpinner. 12 | FOUNDATION_EXPORT double SwiftSpinnerVersionNumber; 13 | 14 | //! Project version string for SwiftSpinner. 15 | FOUNDATION_EXPORT const unsigned char SwiftSpinnerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Sources/SwiftSpinner/SwiftSpinner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015-present Marin Todorov, Underplot ltd. 3 | // This code is distributed under the terms and conditions of the MIT license. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | // 9 | 10 | import UIKit 11 | 12 | public class SwiftSpinner: UIView { 13 | fileprivate static let standardAnimationDuration = 0.33 14 | 15 | // MARK: - Singleton 16 | 17 | // 18 | // Access the singleton instance 19 | // 20 | public static let shared = SwiftSpinner(frame: CGRect.zero) 21 | 22 | // MARK: - Init 23 | 24 | /// Init 25 | /// 26 | /// - Parameter frame: the view's frame 27 | public override init(frame: CGRect) { 28 | currentTitleFont = defaultTitleFont // By default we initialize to the same. 29 | 30 | super.init(frame: frame) 31 | 32 | blurEffect = UIBlurEffect(style: blurEffectStyle) 33 | blurView = UIVisualEffectView() 34 | addSubview(blurView) 35 | 36 | vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: blurEffect)) 37 | addSubview(vibrancyView) 38 | 39 | let titleScale: CGFloat = 0.85 40 | titleLabel.frame.size = CGSize(width: frameSize.width * titleScale, height: frameSize.height * titleScale) 41 | titleLabel.font = currentTitleFont 42 | titleLabel.numberOfLines = 0 43 | titleLabel.textAlignment = .center 44 | titleLabel.lineBreakMode = .byWordWrapping 45 | titleLabel.adjustsFontSizeToFitWidth = true 46 | titleLabel.textColor = UIColor.white 47 | 48 | blurView.contentView.addSubview(titleLabel) 49 | blurView.contentView.addSubview(vibrancyView) 50 | 51 | outerCircleView.frame.size = frameSize 52 | 53 | outerCircle.path = UIBezierPath(ovalIn: CGRect(x: 0.0, y: 0.0, width: frameSize.width, height: frameSize.height)).cgPath 54 | outerCircle.lineWidth = 8.0 55 | outerCircle.strokeStart = 0.0 56 | outerCircle.strokeEnd = 0.45 57 | outerCircle.lineCap = .round 58 | outerCircle.fillColor = UIColor.clear.cgColor 59 | outerCircle.strokeColor = outerCircleDefaultColor 60 | outerCircleView.layer.addSublayer(outerCircle) 61 | 62 | outerCircle.strokeStart = 0.0 63 | outerCircle.strokeEnd = 1.0 64 | 65 | blurView.contentView.addSubview(outerCircleView) 66 | 67 | innerCircleView.frame.size = frameSize 68 | 69 | let innerCirclePadding: CGFloat = 12 70 | innerCircle.path = UIBezierPath(ovalIn: CGRect(x: innerCirclePadding, y: innerCirclePadding, width: frameSize.width - 2*innerCirclePadding, height: frameSize.height - 2*innerCirclePadding)).cgPath 71 | innerCircle.lineWidth = 4.0 72 | innerCircle.strokeStart = 0.5 73 | innerCircle.strokeEnd = 0.9 74 | innerCircle.lineCap = .round 75 | innerCircle.fillColor = UIColor.clear.cgColor 76 | innerCircle.strokeColor = innerCircleDefaultColor 77 | innerCircleView.layer.addSublayer(innerCircle) 78 | 79 | innerCircle.strokeStart = 0.0 80 | innerCircle.strokeEnd = 1.0 81 | 82 | blurView.contentView.addSubview(innerCircleView) 83 | 84 | isUserInteractionEnabled = true 85 | } 86 | 87 | public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 88 | return self 89 | } 90 | 91 | // MARK: - Public interface 92 | 93 | /// The label with the spinner's title 94 | public lazy var titleLabel = UILabel() 95 | 96 | /// The label with the spinner's subtitle 97 | public var subtitleLabel: UILabel? 98 | 99 | private let outerCircleDefaultColor = UIColor.white.cgColor 100 | fileprivate var _outerColor: UIColor? 101 | 102 | /// The color of the outer circle 103 | public var outerColor: UIColor? { 104 | get { return _outerColor } 105 | set(newColor) { 106 | _outerColor = newColor 107 | outerCircle.strokeColor = newColor?.cgColor ?? outerCircleDefaultColor 108 | } 109 | } 110 | 111 | private let innerCircleDefaultColor = UIColor.gray.cgColor 112 | fileprivate var _innerColor: UIColor? 113 | 114 | /// The color of the inner circle 115 | public var innerColor: UIColor? { 116 | get { return _innerColor } 117 | set(newColor) { 118 | _innerColor = newColor 119 | innerCircle.strokeColor = newColor?.cgColor ?? innerCircleDefaultColor 120 | } 121 | } 122 | 123 | /// Custom superview for the spinner 124 | private static weak var customSuperview: UIView? 125 | private static func containerView() -> UIView? { 126 | #if EXTENSION 127 | return customSuperview 128 | #else 129 | if #available(iOS 13, *) { 130 | return customSuperview ?? UIApplication.shared.windows.first{ $0.isKeyWindow } 131 | } else { 132 | return customSuperview ?? UIApplication.shared.keyWindow 133 | } 134 | #endif 135 | } 136 | 137 | /// Custom container for the spinner 138 | public class func useContainerView(_ sv: UIView?) { 139 | customSuperview = sv 140 | } 141 | 142 | /// Show the blurred background. If false the background content will be visible. Defaults to true. 143 | public static var showBlurBackground: Bool = true 144 | 145 | /// Show the spinner activity on screen, if visible only update the title 146 | /// 147 | /// - Parameters: 148 | /// - title: The title shown under the spiiner 149 | /// - animated: Animate the spinner. Defaults to true 150 | /// - Returns: The instance of the spinner 151 | @discardableResult 152 | public class func show(_ title: String, animated: Bool = true) -> SwiftSpinner { 153 | let spinner = SwiftSpinner.shared 154 | 155 | spinner.clearTapHandler() 156 | 157 | spinner.updateFrame() 158 | 159 | if spinner.superview == nil { 160 | // Show the spinner 161 | spinner.blurView.contentView.alpha = 0 162 | 163 | guard let containerView = containerView() else { 164 | #if EXTENSION 165 | fatalError("\n`containerView` is `nil`. `UIApplication.keyWindow` is not available in extensions and so, a containerView is required. Use `useContainerView` to set a view where the spinner should show") 166 | #else 167 | fatalError("\n`UIApplication.keyWindow` is `nil`. If you're trying to show a spinner from your view controller's `viewDidLoad` method, do that from `viewWillAppear` instead. Alternatively use `useContainerView` to set a view where the spinner should show") 168 | #endif 169 | } 170 | 171 | containerView.addSubview(spinner) 172 | 173 | UIView.animate(withDuration: SwiftSpinner.standardAnimationDuration, delay: 0.0, options: .curveEaseOut, animations: { 174 | spinner.blurView.contentView.alpha = 1 175 | spinner.blurView.effect = showBlurBackground ? spinner.blurEffect : .none 176 | }, completion: nil) 177 | 178 | #if os(iOS) 179 | // Orientation change observer 180 | NotificationCenter.default.addObserver( 181 | spinner, 182 | selector: #selector(SwiftSpinner.orientationChangedAction), 183 | name: UIDevice.orientationDidChangeNotification, 184 | object: nil) 185 | #endif 186 | } else if spinner.dismissing { 187 | // If the spinner is hiding, delay the next show. The duration is set to double the standard animation to avoid an edge case that caused endless laoding. See #125 188 | show(delay: SwiftSpinner.standardAnimationDuration, title: title, animated: true) 189 | } 190 | 191 | spinner.title = title 192 | spinner.animating = animated 193 | 194 | return spinner 195 | } 196 | 197 | /// Show the spinner activity on screen with duration, if visible only update the title 198 | /// 199 | /// - Parameters: 200 | /// - duration: The duration of the show animation 201 | /// - title: The title shown under the spinner 202 | /// - animated: Animate the spinner. Defaults to true 203 | /// - completion: An optional completion handler 204 | /// - Returns: The instance of the spinner 205 | @discardableResult 206 | public class func show(duration: Double, title: String, animated: Bool = true, completion: (() -> ())? = nil) -> SwiftSpinner { 207 | let spinner = SwiftSpinner.show(title, animated: animated) 208 | spinner.delay(duration) { 209 | SwiftSpinner.hide { 210 | completion?() 211 | } 212 | } 213 | return spinner 214 | } 215 | 216 | private static var delayedTokens = [String]() 217 | 218 | /// Show the spinner activity on screen, after delay. If new call to show, showWithDelay or hide is maked before execution this call is discarded 219 | /// 220 | /// - Parameters: 221 | /// - delay: The delay time 222 | /// - title: The title shown under the spinner 223 | /// - animated: Animate the spinner. Defaults to true 224 | public class func show(delay: Double, title: String, animated: Bool = true) { 225 | let token = UUID().uuidString 226 | delayedTokens.append(token) 227 | SwiftSpinner.shared.delay(delay, completion: { 228 | if let index = delayedTokens.firstIndex(of: token) { 229 | delayedTokens.remove(at: index) 230 | SwiftSpinner.show(title, animated: animated) 231 | } 232 | }) 233 | } 234 | 235 | /// Show the spinner with the outer circle representing progress (0 to 1) 236 | /// 237 | /// - Parameters: 238 | /// - progress: The progress percentage. Values between 0 and 1 239 | /// - title: The title shown under the spinner 240 | /// - Returns: The instance of the spinner 241 | @discardableResult 242 | public class func show(progress: Double, title: String) -> SwiftSpinner { 243 | let spinner = SwiftSpinner.show(title, animated: false) 244 | spinner.outerCircle.strokeEnd = CGFloat(progress) 245 | return spinner 246 | } 247 | 248 | /// If set to true, hiding a spinner causes scheduled spinners to be canceled 249 | public static var hideCancelsScheduledSpinners = true 250 | 251 | /// Hide the spinner 252 | /// 253 | /// - Parameter completion: A closure called upon completion 254 | public class func hide(_ completion: (() -> Void)? = nil) { 255 | let spinner = SwiftSpinner.shared 256 | 257 | spinner.dismissing = true 258 | 259 | NotificationCenter.default.removeObserver(spinner) 260 | if hideCancelsScheduledSpinners { 261 | delayedTokens.removeAll() 262 | } 263 | 264 | DispatchQueue.main.async(execute: { 265 | spinner.clearTapHandler() 266 | 267 | if spinner.superview == nil { 268 | spinner.dismissing = false 269 | return 270 | } 271 | 272 | UIView.animate(withDuration: SwiftSpinner.standardAnimationDuration, delay: 0.0, options: .curveEaseOut, animations: { 273 | spinner.blurView.contentView.alpha = 0 274 | spinner.blurView.effect = nil 275 | }, completion: {_ in 276 | spinner.blurView.contentView.alpha = 1 277 | spinner.removeFromSuperview() 278 | spinner.titleLabel.text = nil 279 | spinner.dismissing = false 280 | 281 | completion?() 282 | }) 283 | 284 | spinner.animating = false 285 | }) 286 | } 287 | 288 | /// Set the default title font 289 | /// 290 | /// - Parameter font: The title font 291 | public class func setTitleFont(_ font: UIFont?) { 292 | let spinner = SwiftSpinner.shared 293 | 294 | spinner.currentTitleFont = font ?? spinner.defaultTitleFont 295 | spinner.titleLabel.font = font ?? spinner.defaultTitleFont 296 | } 297 | 298 | /// Set the default title color 299 | /// 300 | /// - Parameter color: The title color 301 | public class func setTitleColor(_ color: UIColor?) { 302 | let spinner = SwiftSpinner.shared 303 | 304 | spinner.titleLabel.textColor = color ?? spinner.defaultTitleColor 305 | } 306 | 307 | /// The spinner title 308 | public var title: String = "" { 309 | didSet { 310 | let spinner = SwiftSpinner.shared 311 | 312 | guard spinner.animating else { 313 | spinner.titleLabel.transform = CGAffineTransform.identity 314 | spinner.titleLabel.alpha = 1.0 315 | spinner.titleLabel.text = self.title 316 | return 317 | } 318 | 319 | UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveEaseOut, animations: { 320 | spinner.titleLabel.transform = CGAffineTransform(scaleX: 0.75, y: 0.75) 321 | spinner.titleLabel.alpha = 0.2 322 | }, completion: { _ in 323 | spinner.titleLabel.text = self.title 324 | UIView.animate(withDuration: 0.35, delay: 0.0, usingSpringWithDamping: 0.35, initialSpringVelocity: 0.0, options: [], animations: { 325 | spinner.titleLabel.transform = CGAffineTransform.identity 326 | spinner.titleLabel.alpha = 1.0 327 | }, completion: nil) 328 | }) 329 | } 330 | } 331 | 332 | /// Observe the view frame and update the subviews layout 333 | public override var frame: CGRect { 334 | didSet { 335 | if frame == CGRect.zero { 336 | return 337 | } 338 | blurView.frame = bounds 339 | vibrancyView.frame = blurView.bounds 340 | titleLabel.center = vibrancyView.center 341 | outerCircleView.center = vibrancyView.center 342 | innerCircleView.center = vibrancyView.center 343 | layoutSubtitle() 344 | } 345 | } 346 | 347 | /// Start the spinning animation 348 | public var animating: Bool = false { 349 | 350 | willSet (shouldAnimate) { 351 | if shouldAnimate && !animating { 352 | spinInner() 353 | spinOuter() 354 | } 355 | } 356 | 357 | didSet { 358 | // Update UI 359 | if animating { 360 | self.outerCircle.strokeStart = 0.0 361 | self.outerCircle.strokeEnd = 0.45 362 | self.innerCircle.strokeStart = 0.5 363 | self.innerCircle.strokeEnd = 0.9 364 | } else { 365 | self.outerCircle.strokeStart = 0.0 366 | self.outerCircle.strokeEnd = 1.0 367 | self.innerCircle.strokeStart = 0.0 368 | self.innerCircle.strokeEnd = 1.0 369 | } 370 | } 371 | } 372 | 373 | /// Tap handler 374 | /// 375 | /// - Parameters: 376 | /// - tap: The tap handler closure 377 | /// - subtitleText: The optional subtitle 378 | public func addTapHandler(_ tap: @escaping (() -> Void), subtitle subtitleText: String? = nil) { 379 | clearTapHandler() 380 | 381 | //vibrancyView.contentView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: Selector("didTapSpinner"))) 382 | tapHandler = tap 383 | 384 | if subtitleText != nil { 385 | subtitleLabel = UILabel() 386 | if let subtitle = subtitleLabel { 387 | subtitle.text = subtitleText 388 | subtitle.font = UIFont(name: self.currentTitleFont.familyName, size: currentTitleFont.pointSize * 0.8) 389 | subtitle.textColor = UIColor.white 390 | subtitle.numberOfLines = 0 391 | subtitle.textAlignment = .center 392 | subtitle.lineBreakMode = .byWordWrapping 393 | layoutSubtitle() 394 | vibrancyView.contentView.addSubview(subtitle) 395 | } 396 | } 397 | } 398 | 399 | public override func touchesBegan(_ touches: Set, with event: UIEvent?) { 400 | super.touchesBegan(touches, with: event) 401 | 402 | if tapHandler != nil { 403 | tapHandler?() 404 | tapHandler = nil 405 | } 406 | } 407 | 408 | /// Remove the tap handler 409 | public func clearTapHandler() { 410 | isUserInteractionEnabled = false 411 | subtitleLabel?.removeFromSuperview() 412 | tapHandler = nil 413 | } 414 | 415 | // MARK: - Private interface 416 | 417 | // 418 | // Layout elements 419 | // 420 | 421 | private var blurEffectStyle: UIBlurEffect.Style = .dark 422 | private var blurEffect: UIBlurEffect! 423 | private var blurView: UIVisualEffectView! 424 | private var vibrancyView: UIVisualEffectView! 425 | 426 | private let defaultTitleFont = UIFont(name: "HelveticaNeue", size: 22.0)! 427 | private var currentTitleFont: UIFont 428 | 429 | private var defaultTitleColor = UIColor.white 430 | 431 | let frameSize = CGSize(width: 200.0, height: 200.0) 432 | 433 | private lazy var outerCircleView = UIView() 434 | private lazy var innerCircleView = UIView() 435 | 436 | private let outerCircle = CAShapeLayer() 437 | private let innerCircle = CAShapeLayer() 438 | 439 | required public init?(coder aDecoder: NSCoder) { 440 | fatalError("Not coder compliant") 441 | } 442 | 443 | private var currentOuterRotation: CGFloat = 0.0 444 | private var currentInnerRotation: CGFloat = 0.1 445 | 446 | private var dismissing: Bool = false 447 | 448 | private func spinOuter() { 449 | if superview == nil { 450 | return 451 | } 452 | 453 | let duration = Double(Float(arc4random()) / Float(UInt32.max)) * 2.0 + 1.5 454 | let randomRotation = Double(Float(arc4random()) / Float(UInt32.max)) * (Double.pi / 4) + (Double.pi / 4) 455 | 456 | //outer circle 457 | UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.0, options: [], animations: { 458 | self.currentOuterRotation -= CGFloat(randomRotation) 459 | self.outerCircleView.transform = CGAffineTransform(rotationAngle: self.currentOuterRotation) 460 | }, completion: {_ in 461 | let waitDuration = Double(Float(arc4random()) / Float(UInt32.max)) * 1.0 + 1.0 462 | self.delay(waitDuration, completion: { 463 | if self.animating { 464 | self.spinOuter() 465 | } 466 | }) 467 | }) 468 | } 469 | 470 | private func spinInner() { 471 | if superview == nil { 472 | return 473 | } 474 | 475 | //inner circle 476 | UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: [], animations: { 477 | self.currentInnerRotation += CGFloat(Double.pi / 4) 478 | self.innerCircleView.transform = CGAffineTransform(rotationAngle: self.currentInnerRotation) 479 | }, completion: { _ in 480 | self.delay(0.5, completion: { 481 | if self.animating { 482 | self.spinInner() 483 | } 484 | }) 485 | }) 486 | } 487 | 488 | @objc func orientationChangedAction() { 489 | if let _ = SwiftSpinner.containerView() { 490 | SwiftSpinner.shared.setNeedsLayout() 491 | } 492 | } 493 | 494 | public func updateFrame() { 495 | if let containerView = SwiftSpinner.containerView() { 496 | SwiftSpinner.shared.frame = containerView.bounds 497 | containerView.bringSubviewToFront(SwiftSpinner.shared) 498 | } 499 | } 500 | 501 | // MARK: - Util methods 502 | 503 | func delay(_ seconds: Double, completion:@escaping () -> Void) { 504 | let popTime = DispatchTime.now() + Double(Int64( Double(NSEC_PER_SEC) * seconds )) / Double(NSEC_PER_SEC) 505 | 506 | DispatchQueue.main.asyncAfter(deadline: popTime) { 507 | completion() 508 | } 509 | } 510 | 511 | fileprivate func layoutSubtitle() { 512 | if let subtitle = subtitleLabel { 513 | subtitle.bounds.size = subtitle.sizeThatFits(bounds.insetBy(dx: 20.0, dy: 0.0).size) 514 | var safeArea: CGFloat = 0 515 | if #available(iOS 11.0, tvOS 11.0, *) { 516 | safeArea = superview?.safeAreaInsets.bottom ?? 0 517 | } 518 | subtitle.center = CGPoint(x: bounds.midX, y: bounds.maxY - subtitle.bounds.midY - subtitle.font.pointSize - safeArea) 519 | } 520 | } 521 | 522 | override public func layoutSubviews() { 523 | super.layoutSubviews() 524 | updateFrame() 525 | } 526 | 527 | // MARK: - Tap handler 528 | private var tapHandler: (() -> Void)? 529 | func didTapSpinner() { 530 | tapHandler?() 531 | } 532 | } 533 | -------------------------------------------------------------------------------- /SwiftSpinner.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "SwiftSpinner" 3 | s.version = "2.2.0" 4 | s.summary = "A beautiful activity indicator written in Swift" 5 | s.description = <<-DESC 6 | SwiftSpinner is an extra beautiful activity indicator with plain and bold style fitting. It uses dynamic blur and translucency to overlay the current screen contents and display an activity indicator with text (or the so called “spinner”). 7 | DESC 8 | s.homepage = "https://github.com/icanzilb/SwiftSpinner" 9 | s.screenshots = "https://raw.githubusercontent.com/icanzilb/SwiftSpinner/main/etc/spinner-preview.gif" 10 | s.license = 'MIT' 11 | s.author = { "Marin Todorov" => "touch-code-magazine@underplot.com" } 12 | s.source = { :git => "https://github.com/icanzilb/SwiftSpinner.git", :tag => s.version.to_s } 13 | s.social_media_url = 'https://twitter.com/icanzilb' 14 | 15 | s.ios.deployment_target = '9.0' 16 | s.tvos.deployment_target = '9.0' 17 | 18 | s.requires_arc = true 19 | 20 | s.source_files = 'Sources/SwiftSpinner' 21 | s.frameworks = 'UIKit' 22 | 23 | end 24 | -------------------------------------------------------------------------------- /SwiftSpinner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D20C82FD1C77C1F2002CA000 /* SwiftSpinner.h in Headers */ = {isa = PBXBuildFile; fileRef = D20C82FC1C77C1F2002CA000 /* SwiftSpinner.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | D20C83051C77C2B7002CA000 /* SwiftSpinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C83041C77C2B7002CA000 /* SwiftSpinner.swift */; }; 12 | D20C83151C77C9F9002CA000 /* SwiftSpinner.h in Headers */ = {isa = PBXBuildFile; fileRef = D20C82FC1C77C1F2002CA000 /* SwiftSpinner.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXFileReference section */ 16 | D20C82F91C77C1F2002CA000 /* SwiftSpinner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftSpinner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 17 | D20C82FC1C77C1F2002CA000 /* SwiftSpinner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SwiftSpinner.h; path = ../SwiftSpinner/SwiftSpinner.h; sourceTree = ""; }; 18 | D20C82FE1C77C1F2002CA000 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../SwiftSpinner/Info.plist; sourceTree = ""; }; 19 | D20C83041C77C2B7002CA000 /* SwiftSpinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSpinner.swift; sourceTree = ""; }; 20 | D20C830B1C77C49D002CA000 /* SwiftSpinner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftSpinner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | D20C83131C77C82D002CA000 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; 22 | /* End PBXFileReference section */ 23 | 24 | /* Begin PBXFrameworksBuildPhase section */ 25 | D20C82F51C77C1F1002CA000 /* Frameworks */ = { 26 | isa = PBXFrameworksBuildPhase; 27 | buildActionMask = 2147483647; 28 | files = ( 29 | ); 30 | runOnlyForDeploymentPostprocessing = 0; 31 | }; 32 | D20C83071C77C49D002CA000 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | D20C82EF1C77C1F1002CA000 = { 43 | isa = PBXGroup; 44 | children = ( 45 | D20C82FB1C77C1F2002CA000 /* SwiftSpinner */, 46 | D20C82FA1C77C1F2002CA000 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | D20C82FA1C77C1F2002CA000 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | D20C82F91C77C1F2002CA000 /* SwiftSpinner.framework */, 54 | D20C830B1C77C49D002CA000 /* SwiftSpinner.framework */, 55 | ); 56 | name = Products; 57 | sourceTree = ""; 58 | }; 59 | D20C82FB1C77C1F2002CA000 /* SwiftSpinner */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | D20C83041C77C2B7002CA000 /* SwiftSpinner.swift */, 63 | D20C830C1C77C49D002CA000 /* Supporting Files */, 64 | ); 65 | path = SwiftSpinner; 66 | sourceTree = ""; 67 | }; 68 | D20C830C1C77C49D002CA000 /* Supporting Files */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | D20C82FC1C77C1F2002CA000 /* SwiftSpinner.h */, 72 | D20C83131C77C82D002CA000 /* Info-tvOS.plist */, 73 | D20C82FE1C77C1F2002CA000 /* Info.plist */, 74 | ); 75 | name = "Supporting Files"; 76 | path = SwiftSpinner; 77 | sourceTree = SOURCE_ROOT; 78 | }; 79 | /* End PBXGroup section */ 80 | 81 | /* Begin PBXHeadersBuildPhase section */ 82 | D20C82F61C77C1F1002CA000 /* Headers */ = { 83 | isa = PBXHeadersBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | D20C82FD1C77C1F2002CA000 /* SwiftSpinner.h in Headers */, 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | D20C83081C77C49D002CA000 /* Headers */ = { 91 | isa = PBXHeadersBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | D20C83151C77C9F9002CA000 /* SwiftSpinner.h in Headers */, 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXHeadersBuildPhase section */ 99 | 100 | /* Begin PBXNativeTarget section */ 101 | D20C82F81C77C1F1002CA000 /* SwiftSpinner */ = { 102 | isa = PBXNativeTarget; 103 | buildConfigurationList = D20C83011C77C1F2002CA000 /* Build configuration list for PBXNativeTarget "SwiftSpinner" */; 104 | buildPhases = ( 105 | D20C82F41C77C1F1002CA000 /* Sources */, 106 | D20C82F51C77C1F1002CA000 /* Frameworks */, 107 | D20C82F61C77C1F1002CA000 /* Headers */, 108 | D20C82F71C77C1F1002CA000 /* Resources */, 109 | ); 110 | buildRules = ( 111 | ); 112 | dependencies = ( 113 | ); 114 | name = SwiftSpinner; 115 | productName = SwiftSpinner; 116 | productReference = D20C82F91C77C1F2002CA000 /* SwiftSpinner.framework */; 117 | productType = "com.apple.product-type.framework"; 118 | }; 119 | D20C830A1C77C49D002CA000 /* SwiftSpinner tvOS */ = { 120 | isa = PBXNativeTarget; 121 | buildConfigurationList = D20C83101C77C49D002CA000 /* Build configuration list for PBXNativeTarget "SwiftSpinner tvOS" */; 122 | buildPhases = ( 123 | D20C83061C77C49D002CA000 /* Sources */, 124 | D20C83071C77C49D002CA000 /* Frameworks */, 125 | D20C83081C77C49D002CA000 /* Headers */, 126 | D20C83091C77C49D002CA000 /* Resources */, 127 | ); 128 | buildRules = ( 129 | ); 130 | dependencies = ( 131 | ); 132 | name = "SwiftSpinner tvOS"; 133 | productName = "SwiftSpinner tvOS"; 134 | productReference = D20C830B1C77C49D002CA000 /* SwiftSpinner.framework */; 135 | productType = "com.apple.product-type.framework"; 136 | }; 137 | /* End PBXNativeTarget section */ 138 | 139 | /* Begin PBXProject section */ 140 | D20C82F01C77C1F1002CA000 /* Project object */ = { 141 | isa = PBXProject; 142 | attributes = { 143 | LastUpgradeCheck = 1000; 144 | ORGANIZATIONNAME = "Underplot ltd."; 145 | TargetAttributes = { 146 | D20C82F81C77C1F1002CA000 = { 147 | CreatedOnToolsVersion = 7.2.1; 148 | DevelopmentTeam = 72H5A3LE65; 149 | DevelopmentTeamName = "Andrew King"; 150 | LastSwiftMigration = 1000; 151 | }; 152 | D20C830A1C77C49D002CA000 = { 153 | CreatedOnToolsVersion = 7.2.1; 154 | DevelopmentTeam = 72H5A3LE65; 155 | DevelopmentTeamName = "Andrew King"; 156 | }; 157 | }; 158 | }; 159 | buildConfigurationList = D20C82F31C77C1F1002CA000 /* Build configuration list for PBXProject "SwiftSpinner" */; 160 | compatibilityVersion = "Xcode 3.2"; 161 | developmentRegion = en; 162 | hasScannedForEncodings = 0; 163 | knownRegions = ( 164 | en, 165 | Base, 166 | ); 167 | mainGroup = D20C82EF1C77C1F1002CA000; 168 | productRefGroup = D20C82FA1C77C1F2002CA000 /* Products */; 169 | projectDirPath = ""; 170 | projectRoot = ""; 171 | targets = ( 172 | D20C82F81C77C1F1002CA000 /* SwiftSpinner */, 173 | D20C830A1C77C49D002CA000 /* SwiftSpinner tvOS */, 174 | ); 175 | }; 176 | /* End PBXProject section */ 177 | 178 | /* Begin PBXResourcesBuildPhase section */ 179 | D20C82F71C77C1F1002CA000 /* Resources */ = { 180 | isa = PBXResourcesBuildPhase; 181 | buildActionMask = 2147483647; 182 | files = ( 183 | ); 184 | runOnlyForDeploymentPostprocessing = 0; 185 | }; 186 | D20C83091C77C49D002CA000 /* Resources */ = { 187 | isa = PBXResourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | runOnlyForDeploymentPostprocessing = 0; 192 | }; 193 | /* End PBXResourcesBuildPhase section */ 194 | 195 | /* Begin PBXSourcesBuildPhase section */ 196 | D20C82F41C77C1F1002CA000 /* Sources */ = { 197 | isa = PBXSourcesBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | D20C83051C77C2B7002CA000 /* SwiftSpinner.swift in Sources */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | D20C83061C77C49D002CA000 /* Sources */ = { 205 | isa = PBXSourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXSourcesBuildPhase section */ 212 | 213 | /* Begin XCBuildConfiguration section */ 214 | D20C82FF1C77C1F2002CA000 /* Debug */ = { 215 | isa = XCBuildConfiguration; 216 | buildSettings = { 217 | ALWAYS_SEARCH_USER_PATHS = NO; 218 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 219 | CLANG_CXX_LIBRARY = "libc++"; 220 | CLANG_ENABLE_MODULES = YES; 221 | CLANG_ENABLE_OBJC_ARC = YES; 222 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 223 | CLANG_WARN_BOOL_CONVERSION = YES; 224 | CLANG_WARN_COMMA = YES; 225 | CLANG_WARN_CONSTANT_CONVERSION = YES; 226 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 227 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 228 | CLANG_WARN_EMPTY_BODY = YES; 229 | CLANG_WARN_ENUM_CONVERSION = YES; 230 | CLANG_WARN_INFINITE_RECURSION = YES; 231 | CLANG_WARN_INT_CONVERSION = YES; 232 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 233 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 234 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 235 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 236 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 237 | CLANG_WARN_STRICT_PROTOTYPES = YES; 238 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 239 | CLANG_WARN_UNREACHABLE_CODE = YES; 240 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 241 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 242 | COPY_PHASE_STRIP = NO; 243 | CURRENT_PROJECT_VERSION = 1; 244 | DEBUG_INFORMATION_FORMAT = dwarf; 245 | ENABLE_STRICT_OBJC_MSGSEND = YES; 246 | ENABLE_TESTABILITY = YES; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_DYNAMIC_NO_PIC = NO; 249 | GCC_NO_COMMON_BLOCKS = YES; 250 | GCC_OPTIMIZATION_LEVEL = 0; 251 | GCC_PREPROCESSOR_DEFINITIONS = ( 252 | "DEBUG=1", 253 | "$(inherited)", 254 | ); 255 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 256 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 257 | GCC_WARN_UNDECLARED_SELECTOR = YES; 258 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 259 | GCC_WARN_UNUSED_FUNCTION = YES; 260 | GCC_WARN_UNUSED_VARIABLE = YES; 261 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 262 | MTL_ENABLE_DEBUG_INFO = YES; 263 | ONLY_ACTIVE_ARCH = YES; 264 | SDKROOT = iphoneos; 265 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 266 | SWIFT_VERSION = 5.0; 267 | TARGETED_DEVICE_FAMILY = "1,2"; 268 | VERSIONING_SYSTEM = "apple-generic"; 269 | VERSION_INFO_PREFIX = ""; 270 | }; 271 | name = Debug; 272 | }; 273 | D20C83001C77C1F2002CA000 /* Release */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 278 | CLANG_CXX_LIBRARY = "libc++"; 279 | CLANG_ENABLE_MODULES = YES; 280 | CLANG_ENABLE_OBJC_ARC = YES; 281 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 282 | CLANG_WARN_BOOL_CONVERSION = YES; 283 | CLANG_WARN_COMMA = YES; 284 | CLANG_WARN_CONSTANT_CONVERSION = YES; 285 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 287 | CLANG_WARN_EMPTY_BODY = YES; 288 | CLANG_WARN_ENUM_CONVERSION = YES; 289 | CLANG_WARN_INFINITE_RECURSION = YES; 290 | CLANG_WARN_INT_CONVERSION = YES; 291 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 292 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 293 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 294 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 295 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 296 | CLANG_WARN_STRICT_PROTOTYPES = YES; 297 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 298 | CLANG_WARN_UNREACHABLE_CODE = YES; 299 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 300 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 301 | COPY_PHASE_STRIP = NO; 302 | CURRENT_PROJECT_VERSION = 1; 303 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 304 | ENABLE_NS_ASSERTIONS = NO; 305 | ENABLE_STRICT_OBJC_MSGSEND = YES; 306 | GCC_C_LANGUAGE_STANDARD = gnu99; 307 | GCC_NO_COMMON_BLOCKS = YES; 308 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 309 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 310 | GCC_WARN_UNDECLARED_SELECTOR = YES; 311 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 312 | GCC_WARN_UNUSED_FUNCTION = YES; 313 | GCC_WARN_UNUSED_VARIABLE = YES; 314 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 315 | MTL_ENABLE_DEBUG_INFO = NO; 316 | SDKROOT = iphoneos; 317 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 318 | SWIFT_VERSION = 5.0; 319 | TARGETED_DEVICE_FAMILY = "1,2"; 320 | VALIDATE_PRODUCT = YES; 321 | VERSIONING_SYSTEM = "apple-generic"; 322 | VERSION_INFO_PREFIX = ""; 323 | }; 324 | name = Release; 325 | }; 326 | D20C83021C77C1F2002CA000 /* Debug */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | CLANG_ENABLE_MODULES = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 331 | DEFINES_MODULE = YES; 332 | DYLIB_COMPATIBILITY_VERSION = 1; 333 | DYLIB_CURRENT_VERSION = 1; 334 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 335 | INFOPLIST_FILE = SwiftSpinner/Info.plist; 336 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 337 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 338 | PRODUCT_BUNDLE_IDENTIFIER = com.underplot.SwiftSpinner; 339 | PRODUCT_NAME = "$(TARGET_NAME)"; 340 | SKIP_INSTALL = YES; 341 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 342 | SWIFT_VERSION = 5.0; 343 | }; 344 | name = Debug; 345 | }; 346 | D20C83031C77C1F2002CA000 /* Release */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | CLANG_ENABLE_MODULES = YES; 350 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 351 | DEFINES_MODULE = YES; 352 | DYLIB_COMPATIBILITY_VERSION = 1; 353 | DYLIB_CURRENT_VERSION = 1; 354 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 355 | INFOPLIST_FILE = SwiftSpinner/Info.plist; 356 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 357 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 358 | PRODUCT_BUNDLE_IDENTIFIER = com.underplot.SwiftSpinner; 359 | PRODUCT_NAME = "$(TARGET_NAME)"; 360 | SKIP_INSTALL = YES; 361 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 362 | SWIFT_VERSION = 5.0; 363 | }; 364 | name = Release; 365 | }; 366 | D20C83111C77C49D002CA000 /* Debug */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 370 | DEFINES_MODULE = YES; 371 | DYLIB_COMPATIBILITY_VERSION = 1; 372 | DYLIB_CURRENT_VERSION = 1; 373 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 374 | INFOPLIST_FILE = "SwiftSpinner/Info-tvOS.plist"; 375 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 377 | PRODUCT_BUNDLE_IDENTIFIER = com.underplot.SwiftSpinner; 378 | PRODUCT_NAME = SwiftSpinner; 379 | SDKROOT = appletvos; 380 | SKIP_INSTALL = YES; 381 | TARGETED_DEVICE_FAMILY = 3; 382 | TVOS_DEPLOYMENT_TARGET = 9.1; 383 | }; 384 | name = Debug; 385 | }; 386 | D20C83121C77C49D002CA000 /* Release */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 390 | DEFINES_MODULE = YES; 391 | DYLIB_COMPATIBILITY_VERSION = 1; 392 | DYLIB_CURRENT_VERSION = 1; 393 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 394 | INFOPLIST_FILE = "SwiftSpinner/Info-tvOS.plist"; 395 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 396 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 397 | PRODUCT_BUNDLE_IDENTIFIER = com.underplot.SwiftSpinner; 398 | PRODUCT_NAME = SwiftSpinner; 399 | SDKROOT = appletvos; 400 | SKIP_INSTALL = YES; 401 | TARGETED_DEVICE_FAMILY = 3; 402 | TVOS_DEPLOYMENT_TARGET = 9.1; 403 | }; 404 | name = Release; 405 | }; 406 | /* End XCBuildConfiguration section */ 407 | 408 | /* Begin XCConfigurationList section */ 409 | D20C82F31C77C1F1002CA000 /* Build configuration list for PBXProject "SwiftSpinner" */ = { 410 | isa = XCConfigurationList; 411 | buildConfigurations = ( 412 | D20C82FF1C77C1F2002CA000 /* Debug */, 413 | D20C83001C77C1F2002CA000 /* Release */, 414 | ); 415 | defaultConfigurationIsVisible = 0; 416 | defaultConfigurationName = Release; 417 | }; 418 | D20C83011C77C1F2002CA000 /* Build configuration list for PBXNativeTarget "SwiftSpinner" */ = { 419 | isa = XCConfigurationList; 420 | buildConfigurations = ( 421 | D20C83021C77C1F2002CA000 /* Debug */, 422 | D20C83031C77C1F2002CA000 /* Release */, 423 | ); 424 | defaultConfigurationIsVisible = 0; 425 | defaultConfigurationName = Release; 426 | }; 427 | D20C83101C77C49D002CA000 /* Build configuration list for PBXNativeTarget "SwiftSpinner tvOS" */ = { 428 | isa = XCConfigurationList; 429 | buildConfigurations = ( 430 | D20C83111C77C49D002CA000 /* Debug */, 431 | D20C83121C77C49D002CA000 /* Release */, 432 | ); 433 | defaultConfigurationIsVisible = 0; 434 | defaultConfigurationName = Release; 435 | }; 436 | /* End XCConfigurationList section */ 437 | }; 438 | rootObject = D20C82F01C77C1F1002CA000 /* Project object */; 439 | } 440 | -------------------------------------------------------------------------------- /SwiftSpinner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftSpinner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftSpinner.xcodeproj/xcshareddata/xcschemes/SwiftSpinner tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /SwiftSpinner.xcodeproj/xcshareddata/xcschemes/SwiftSpinner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /etc/Assets.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/etc/Assets.sketch -------------------------------------------------------------------------------- /etc/spinner-preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icanzilb/SwiftSpinner/b6c6a947025ad19932a81ff1a09ce2b6fe479d76/etc/spinner-preview.gif --------------------------------------------------------------------------------