├── LoadingView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── wangcong.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── wangcong.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── LoadingView ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CGRect+Extension.swift ├── Info.plist ├── UIView+Extension.swift ├── ViewController.swift ├── XLoadingView.swift ├── icon_loading@2x.png ├── icon_loading@3x.png ├── icon_loading_shadow@2x.png ├── icon_loading_shadow@3x.png ├── icon_prompt@2x.png └── icon_prompt@3x.png ├── LoadingViewTests ├── Info.plist └── LoadingViewTests.swift ├── LoadingViewUITests ├── Info.plist └── LoadingViewUITests.swift ├── README.md └── xloadingview.gif /LoadingView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6E12CBEA21A80B0500D9B925 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E12CBE921A80B0500D9B925 /* AppDelegate.swift */; }; 11 | 6E12CBEC21A80B0500D9B925 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E12CBEB21A80B0500D9B925 /* ViewController.swift */; }; 12 | 6E12CBEF21A80B0500D9B925 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CBED21A80B0500D9B925 /* Main.storyboard */; }; 13 | 6E12CBF121A80B0600D9B925 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CBF021A80B0600D9B925 /* Assets.xcassets */; }; 14 | 6E12CBF421A80B0600D9B925 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CBF221A80B0600D9B925 /* LaunchScreen.storyboard */; }; 15 | 6E12CBFF21A80B0600D9B925 /* LoadingViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E12CBFE21A80B0600D9B925 /* LoadingViewTests.swift */; }; 16 | 6E12CC0A21A80B0700D9B925 /* LoadingViewUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E12CC0921A80B0700D9B925 /* LoadingViewUITests.swift */; }; 17 | 6E12CC2021A80B2F00D9B925 /* icon_prompt@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CC1721A80B2E00D9B925 /* icon_prompt@3x.png */; }; 18 | 6E12CC2121A80B2F00D9B925 /* icon_loading@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CC1821A80B2E00D9B925 /* icon_loading@3x.png */; }; 19 | 6E12CC2221A80B2F00D9B925 /* icon_loading_shadow@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CC1921A80B2E00D9B925 /* icon_loading_shadow@3x.png */; }; 20 | 6E12CC2321A80B2F00D9B925 /* icon_loading@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CC1A21A80B2E00D9B925 /* icon_loading@2x.png */; }; 21 | 6E12CC2421A80B2F00D9B925 /* XLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E12CC1B21A80B2E00D9B925 /* XLoadingView.swift */; }; 22 | 6E12CC2521A80B2F00D9B925 /* CGRect+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E12CC1C21A80B2E00D9B925 /* CGRect+Extension.swift */; }; 23 | 6E12CC2621A80B2F00D9B925 /* icon_prompt@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CC1D21A80B2F00D9B925 /* icon_prompt@2x.png */; }; 24 | 6E12CC2721A80B2F00D9B925 /* icon_loading_shadow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6E12CC1E21A80B2F00D9B925 /* icon_loading_shadow@2x.png */; }; 25 | 6E12CC2821A80B2F00D9B925 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E12CC1F21A80B2F00D9B925 /* UIView+Extension.swift */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 6E12CBFB21A80B0600D9B925 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 6E12CBDE21A80B0500D9B925 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 6E12CBE521A80B0500D9B925; 34 | remoteInfo = LoadingView; 35 | }; 36 | 6E12CC0621A80B0700D9B925 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 6E12CBDE21A80B0500D9B925 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 6E12CBE521A80B0500D9B925; 41 | remoteInfo = LoadingView; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 6E12CBE621A80B0500D9B925 /* LoadingView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LoadingView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 6E12CBE921A80B0500D9B925 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 48 | 6E12CBEB21A80B0500D9B925 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 49 | 6E12CBEE21A80B0500D9B925 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 50 | 6E12CBF021A80B0600D9B925 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 51 | 6E12CBF321A80B0600D9B925 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 52 | 6E12CBF521A80B0600D9B925 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | 6E12CBFA21A80B0600D9B925 /* LoadingViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LoadingViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 6E12CBFE21A80B0600D9B925 /* LoadingViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewTests.swift; sourceTree = ""; }; 55 | 6E12CC0021A80B0600D9B925 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 6E12CC0521A80B0600D9B925 /* LoadingViewUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LoadingViewUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 6E12CC0921A80B0700D9B925 /* LoadingViewUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewUITests.swift; sourceTree = ""; }; 58 | 6E12CC0B21A80B0700D9B925 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | 6E12CC1721A80B2E00D9B925 /* icon_prompt@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_prompt@3x.png"; sourceTree = ""; }; 60 | 6E12CC1821A80B2E00D9B925 /* icon_loading@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_loading@3x.png"; sourceTree = ""; }; 61 | 6E12CC1921A80B2E00D9B925 /* icon_loading_shadow@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_loading_shadow@3x.png"; sourceTree = ""; }; 62 | 6E12CC1A21A80B2E00D9B925 /* icon_loading@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_loading@2x.png"; sourceTree = ""; }; 63 | 6E12CC1B21A80B2E00D9B925 /* XLoadingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XLoadingView.swift; sourceTree = ""; }; 64 | 6E12CC1C21A80B2E00D9B925 /* CGRect+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGRect+Extension.swift"; sourceTree = ""; }; 65 | 6E12CC1D21A80B2F00D9B925 /* icon_prompt@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_prompt@2x.png"; sourceTree = ""; }; 66 | 6E12CC1E21A80B2F00D9B925 /* icon_loading_shadow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_loading_shadow@2x.png"; sourceTree = ""; }; 67 | 6E12CC1F21A80B2F00D9B925 /* UIView+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = ""; }; 68 | /* End PBXFileReference section */ 69 | 70 | /* Begin PBXFrameworksBuildPhase section */ 71 | 6E12CBE321A80B0500D9B925 /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | 6E12CBF721A80B0600D9B925 /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | 6E12CC0221A80B0600D9B925 /* Frameworks */ = { 86 | isa = PBXFrameworksBuildPhase; 87 | buildActionMask = 2147483647; 88 | files = ( 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXFrameworksBuildPhase section */ 93 | 94 | /* Begin PBXGroup section */ 95 | 6E12CBDD21A80B0500D9B925 = { 96 | isa = PBXGroup; 97 | children = ( 98 | 6E12CBE821A80B0500D9B925 /* LoadingView */, 99 | 6E12CBFD21A80B0600D9B925 /* LoadingViewTests */, 100 | 6E12CC0821A80B0700D9B925 /* LoadingViewUITests */, 101 | 6E12CBE721A80B0500D9B925 /* Products */, 102 | ); 103 | sourceTree = ""; 104 | }; 105 | 6E12CBE721A80B0500D9B925 /* Products */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 6E12CBE621A80B0500D9B925 /* LoadingView.app */, 109 | 6E12CBFA21A80B0600D9B925 /* LoadingViewTests.xctest */, 110 | 6E12CC0521A80B0600D9B925 /* LoadingViewUITests.xctest */, 111 | ); 112 | name = Products; 113 | sourceTree = ""; 114 | }; 115 | 6E12CBE821A80B0500D9B925 /* LoadingView */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 6E12CC1C21A80B2E00D9B925 /* CGRect+Extension.swift */, 119 | 6E12CC1E21A80B2F00D9B925 /* icon_loading_shadow@2x.png */, 120 | 6E12CC1921A80B2E00D9B925 /* icon_loading_shadow@3x.png */, 121 | 6E12CC1A21A80B2E00D9B925 /* icon_loading@2x.png */, 122 | 6E12CC1821A80B2E00D9B925 /* icon_loading@3x.png */, 123 | 6E12CC1D21A80B2F00D9B925 /* icon_prompt@2x.png */, 124 | 6E12CC1721A80B2E00D9B925 /* icon_prompt@3x.png */, 125 | 6E12CC1F21A80B2F00D9B925 /* UIView+Extension.swift */, 126 | 6E12CC1B21A80B2E00D9B925 /* XLoadingView.swift */, 127 | 6E12CBE921A80B0500D9B925 /* AppDelegate.swift */, 128 | 6E12CBEB21A80B0500D9B925 /* ViewController.swift */, 129 | 6E12CBED21A80B0500D9B925 /* Main.storyboard */, 130 | 6E12CBF021A80B0600D9B925 /* Assets.xcassets */, 131 | 6E12CBF221A80B0600D9B925 /* LaunchScreen.storyboard */, 132 | 6E12CBF521A80B0600D9B925 /* Info.plist */, 133 | ); 134 | path = LoadingView; 135 | sourceTree = ""; 136 | }; 137 | 6E12CBFD21A80B0600D9B925 /* LoadingViewTests */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 6E12CBFE21A80B0600D9B925 /* LoadingViewTests.swift */, 141 | 6E12CC0021A80B0600D9B925 /* Info.plist */, 142 | ); 143 | path = LoadingViewTests; 144 | sourceTree = ""; 145 | }; 146 | 6E12CC0821A80B0700D9B925 /* LoadingViewUITests */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 6E12CC0921A80B0700D9B925 /* LoadingViewUITests.swift */, 150 | 6E12CC0B21A80B0700D9B925 /* Info.plist */, 151 | ); 152 | path = LoadingViewUITests; 153 | sourceTree = ""; 154 | }; 155 | /* End PBXGroup section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | 6E12CBE521A80B0500D9B925 /* LoadingView */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 6E12CC0E21A80B0700D9B925 /* Build configuration list for PBXNativeTarget "LoadingView" */; 161 | buildPhases = ( 162 | 6E12CBE221A80B0500D9B925 /* Sources */, 163 | 6E12CBE321A80B0500D9B925 /* Frameworks */, 164 | 6E12CBE421A80B0500D9B925 /* Resources */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = LoadingView; 171 | productName = LoadingView; 172 | productReference = 6E12CBE621A80B0500D9B925 /* LoadingView.app */; 173 | productType = "com.apple.product-type.application"; 174 | }; 175 | 6E12CBF921A80B0600D9B925 /* LoadingViewTests */ = { 176 | isa = PBXNativeTarget; 177 | buildConfigurationList = 6E12CC1121A80B0700D9B925 /* Build configuration list for PBXNativeTarget "LoadingViewTests" */; 178 | buildPhases = ( 179 | 6E12CBF621A80B0600D9B925 /* Sources */, 180 | 6E12CBF721A80B0600D9B925 /* Frameworks */, 181 | 6E12CBF821A80B0600D9B925 /* Resources */, 182 | ); 183 | buildRules = ( 184 | ); 185 | dependencies = ( 186 | 6E12CBFC21A80B0600D9B925 /* PBXTargetDependency */, 187 | ); 188 | name = LoadingViewTests; 189 | productName = LoadingViewTests; 190 | productReference = 6E12CBFA21A80B0600D9B925 /* LoadingViewTests.xctest */; 191 | productType = "com.apple.product-type.bundle.unit-test"; 192 | }; 193 | 6E12CC0421A80B0600D9B925 /* LoadingViewUITests */ = { 194 | isa = PBXNativeTarget; 195 | buildConfigurationList = 6E12CC1421A80B0700D9B925 /* Build configuration list for PBXNativeTarget "LoadingViewUITests" */; 196 | buildPhases = ( 197 | 6E12CC0121A80B0600D9B925 /* Sources */, 198 | 6E12CC0221A80B0600D9B925 /* Frameworks */, 199 | 6E12CC0321A80B0600D9B925 /* Resources */, 200 | ); 201 | buildRules = ( 202 | ); 203 | dependencies = ( 204 | 6E12CC0721A80B0700D9B925 /* PBXTargetDependency */, 205 | ); 206 | name = LoadingViewUITests; 207 | productName = LoadingViewUITests; 208 | productReference = 6E12CC0521A80B0600D9B925 /* LoadingViewUITests.xctest */; 209 | productType = "com.apple.product-type.bundle.ui-testing"; 210 | }; 211 | /* End PBXNativeTarget section */ 212 | 213 | /* Begin PBXProject section */ 214 | 6E12CBDE21A80B0500D9B925 /* Project object */ = { 215 | isa = PBXProject; 216 | attributes = { 217 | LastSwiftUpdateCheck = 0940; 218 | LastUpgradeCheck = 0940; 219 | ORGANIZATIONNAME = wangcong; 220 | TargetAttributes = { 221 | 6E12CBE521A80B0500D9B925 = { 222 | CreatedOnToolsVersion = 9.4; 223 | }; 224 | 6E12CBF921A80B0600D9B925 = { 225 | CreatedOnToolsVersion = 9.4; 226 | TestTargetID = 6E12CBE521A80B0500D9B925; 227 | }; 228 | 6E12CC0421A80B0600D9B925 = { 229 | CreatedOnToolsVersion = 9.4; 230 | TestTargetID = 6E12CBE521A80B0500D9B925; 231 | }; 232 | }; 233 | }; 234 | buildConfigurationList = 6E12CBE121A80B0500D9B925 /* Build configuration list for PBXProject "LoadingView" */; 235 | compatibilityVersion = "Xcode 9.3"; 236 | developmentRegion = en; 237 | hasScannedForEncodings = 0; 238 | knownRegions = ( 239 | en, 240 | Base, 241 | ); 242 | mainGroup = 6E12CBDD21A80B0500D9B925; 243 | productRefGroup = 6E12CBE721A80B0500D9B925 /* Products */; 244 | projectDirPath = ""; 245 | projectRoot = ""; 246 | targets = ( 247 | 6E12CBE521A80B0500D9B925 /* LoadingView */, 248 | 6E12CBF921A80B0600D9B925 /* LoadingViewTests */, 249 | 6E12CC0421A80B0600D9B925 /* LoadingViewUITests */, 250 | ); 251 | }; 252 | /* End PBXProject section */ 253 | 254 | /* Begin PBXResourcesBuildPhase section */ 255 | 6E12CBE421A80B0500D9B925 /* Resources */ = { 256 | isa = PBXResourcesBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | 6E12CC2121A80B2F00D9B925 /* icon_loading@3x.png in Resources */, 260 | 6E12CC2721A80B2F00D9B925 /* icon_loading_shadow@2x.png in Resources */, 261 | 6E12CC2621A80B2F00D9B925 /* icon_prompt@2x.png in Resources */, 262 | 6E12CC2221A80B2F00D9B925 /* icon_loading_shadow@3x.png in Resources */, 263 | 6E12CC2321A80B2F00D9B925 /* icon_loading@2x.png in Resources */, 264 | 6E12CBF421A80B0600D9B925 /* LaunchScreen.storyboard in Resources */, 265 | 6E12CBF121A80B0600D9B925 /* Assets.xcassets in Resources */, 266 | 6E12CC2021A80B2F00D9B925 /* icon_prompt@3x.png in Resources */, 267 | 6E12CBEF21A80B0500D9B925 /* Main.storyboard in Resources */, 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | }; 271 | 6E12CBF821A80B0600D9B925 /* Resources */ = { 272 | isa = PBXResourcesBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | }; 278 | 6E12CC0321A80B0600D9B925 /* Resources */ = { 279 | isa = PBXResourcesBuildPhase; 280 | buildActionMask = 2147483647; 281 | files = ( 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | /* End PBXResourcesBuildPhase section */ 286 | 287 | /* Begin PBXSourcesBuildPhase section */ 288 | 6E12CBE221A80B0500D9B925 /* Sources */ = { 289 | isa = PBXSourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | 6E12CBEC21A80B0500D9B925 /* ViewController.swift in Sources */, 293 | 6E12CC2521A80B2F00D9B925 /* CGRect+Extension.swift in Sources */, 294 | 6E12CC2421A80B2F00D9B925 /* XLoadingView.swift in Sources */, 295 | 6E12CC2821A80B2F00D9B925 /* UIView+Extension.swift in Sources */, 296 | 6E12CBEA21A80B0500D9B925 /* AppDelegate.swift in Sources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | 6E12CBF621A80B0600D9B925 /* Sources */ = { 301 | isa = PBXSourcesBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | 6E12CBFF21A80B0600D9B925 /* LoadingViewTests.swift in Sources */, 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | 6E12CC0121A80B0600D9B925 /* Sources */ = { 309 | isa = PBXSourcesBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | 6E12CC0A21A80B0700D9B925 /* LoadingViewUITests.swift in Sources */, 313 | ); 314 | runOnlyForDeploymentPostprocessing = 0; 315 | }; 316 | /* End PBXSourcesBuildPhase section */ 317 | 318 | /* Begin PBXTargetDependency section */ 319 | 6E12CBFC21A80B0600D9B925 /* PBXTargetDependency */ = { 320 | isa = PBXTargetDependency; 321 | target = 6E12CBE521A80B0500D9B925 /* LoadingView */; 322 | targetProxy = 6E12CBFB21A80B0600D9B925 /* PBXContainerItemProxy */; 323 | }; 324 | 6E12CC0721A80B0700D9B925 /* PBXTargetDependency */ = { 325 | isa = PBXTargetDependency; 326 | target = 6E12CBE521A80B0500D9B925 /* LoadingView */; 327 | targetProxy = 6E12CC0621A80B0700D9B925 /* PBXContainerItemProxy */; 328 | }; 329 | /* End PBXTargetDependency section */ 330 | 331 | /* Begin PBXVariantGroup section */ 332 | 6E12CBED21A80B0500D9B925 /* Main.storyboard */ = { 333 | isa = PBXVariantGroup; 334 | children = ( 335 | 6E12CBEE21A80B0500D9B925 /* Base */, 336 | ); 337 | name = Main.storyboard; 338 | sourceTree = ""; 339 | }; 340 | 6E12CBF221A80B0600D9B925 /* LaunchScreen.storyboard */ = { 341 | isa = PBXVariantGroup; 342 | children = ( 343 | 6E12CBF321A80B0600D9B925 /* Base */, 344 | ); 345 | name = LaunchScreen.storyboard; 346 | sourceTree = ""; 347 | }; 348 | /* End PBXVariantGroup section */ 349 | 350 | /* Begin XCBuildConfiguration section */ 351 | 6E12CC0C21A80B0700D9B925 /* Debug */ = { 352 | isa = XCBuildConfiguration; 353 | buildSettings = { 354 | ALWAYS_SEARCH_USER_PATHS = NO; 355 | CLANG_ANALYZER_NONNULL = YES; 356 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 357 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 358 | CLANG_CXX_LIBRARY = "libc++"; 359 | CLANG_ENABLE_MODULES = YES; 360 | CLANG_ENABLE_OBJC_ARC = YES; 361 | CLANG_ENABLE_OBJC_WEAK = YES; 362 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 363 | CLANG_WARN_BOOL_CONVERSION = YES; 364 | CLANG_WARN_COMMA = YES; 365 | CLANG_WARN_CONSTANT_CONVERSION = YES; 366 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 367 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 368 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 369 | CLANG_WARN_EMPTY_BODY = YES; 370 | CLANG_WARN_ENUM_CONVERSION = YES; 371 | CLANG_WARN_INFINITE_RECURSION = YES; 372 | CLANG_WARN_INT_CONVERSION = YES; 373 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 374 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 375 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 376 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 377 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 378 | CLANG_WARN_STRICT_PROTOTYPES = YES; 379 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 380 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 381 | CLANG_WARN_UNREACHABLE_CODE = YES; 382 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 383 | CODE_SIGN_IDENTITY = "iPhone Developer"; 384 | COPY_PHASE_STRIP = NO; 385 | DEBUG_INFORMATION_FORMAT = dwarf; 386 | ENABLE_STRICT_OBJC_MSGSEND = YES; 387 | ENABLE_TESTABILITY = YES; 388 | GCC_C_LANGUAGE_STANDARD = gnu11; 389 | GCC_DYNAMIC_NO_PIC = NO; 390 | GCC_NO_COMMON_BLOCKS = YES; 391 | GCC_OPTIMIZATION_LEVEL = 0; 392 | GCC_PREPROCESSOR_DEFINITIONS = ( 393 | "DEBUG=1", 394 | "$(inherited)", 395 | ); 396 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 397 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 398 | GCC_WARN_UNDECLARED_SELECTOR = YES; 399 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 400 | GCC_WARN_UNUSED_FUNCTION = YES; 401 | GCC_WARN_UNUSED_VARIABLE = YES; 402 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 403 | MTL_ENABLE_DEBUG_INFO = YES; 404 | ONLY_ACTIVE_ARCH = YES; 405 | SDKROOT = iphoneos; 406 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 407 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 408 | }; 409 | name = Debug; 410 | }; 411 | 6E12CC0D21A80B0700D9B925 /* Release */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | ALWAYS_SEARCH_USER_PATHS = NO; 415 | CLANG_ANALYZER_NONNULL = YES; 416 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 417 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 418 | CLANG_CXX_LIBRARY = "libc++"; 419 | CLANG_ENABLE_MODULES = YES; 420 | CLANG_ENABLE_OBJC_ARC = YES; 421 | CLANG_ENABLE_OBJC_WEAK = YES; 422 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 423 | CLANG_WARN_BOOL_CONVERSION = YES; 424 | CLANG_WARN_COMMA = YES; 425 | CLANG_WARN_CONSTANT_CONVERSION = YES; 426 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 427 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 428 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 429 | CLANG_WARN_EMPTY_BODY = YES; 430 | CLANG_WARN_ENUM_CONVERSION = YES; 431 | CLANG_WARN_INFINITE_RECURSION = YES; 432 | CLANG_WARN_INT_CONVERSION = YES; 433 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 434 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 435 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 436 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 437 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 438 | CLANG_WARN_STRICT_PROTOTYPES = YES; 439 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 440 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 441 | CLANG_WARN_UNREACHABLE_CODE = YES; 442 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 443 | CODE_SIGN_IDENTITY = "iPhone Developer"; 444 | COPY_PHASE_STRIP = NO; 445 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 446 | ENABLE_NS_ASSERTIONS = NO; 447 | ENABLE_STRICT_OBJC_MSGSEND = YES; 448 | GCC_C_LANGUAGE_STANDARD = gnu11; 449 | GCC_NO_COMMON_BLOCKS = YES; 450 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 451 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 452 | GCC_WARN_UNDECLARED_SELECTOR = YES; 453 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 454 | GCC_WARN_UNUSED_FUNCTION = YES; 455 | GCC_WARN_UNUSED_VARIABLE = YES; 456 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 457 | MTL_ENABLE_DEBUG_INFO = NO; 458 | SDKROOT = iphoneos; 459 | SWIFT_COMPILATION_MODE = wholemodule; 460 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 461 | VALIDATE_PRODUCT = YES; 462 | }; 463 | name = Release; 464 | }; 465 | 6E12CC0F21A80B0700D9B925 /* Debug */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 469 | CODE_SIGN_STYLE = Automatic; 470 | INFOPLIST_FILE = LoadingView/Info.plist; 471 | LD_RUNPATH_SEARCH_PATHS = ( 472 | "$(inherited)", 473 | "@executable_path/Frameworks", 474 | ); 475 | PRODUCT_BUNDLE_IDENTIFIER = com.xswift.LoadingView; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | SWIFT_VERSION = 4.0; 478 | TARGETED_DEVICE_FAMILY = "1,2"; 479 | }; 480 | name = Debug; 481 | }; 482 | 6E12CC1021A80B0700D9B925 /* Release */ = { 483 | isa = XCBuildConfiguration; 484 | buildSettings = { 485 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 486 | CODE_SIGN_STYLE = Automatic; 487 | INFOPLIST_FILE = LoadingView/Info.plist; 488 | LD_RUNPATH_SEARCH_PATHS = ( 489 | "$(inherited)", 490 | "@executable_path/Frameworks", 491 | ); 492 | PRODUCT_BUNDLE_IDENTIFIER = com.xswift.LoadingView; 493 | PRODUCT_NAME = "$(TARGET_NAME)"; 494 | SWIFT_VERSION = 4.0; 495 | TARGETED_DEVICE_FAMILY = "1,2"; 496 | }; 497 | name = Release; 498 | }; 499 | 6E12CC1221A80B0700D9B925 /* Debug */ = { 500 | isa = XCBuildConfiguration; 501 | buildSettings = { 502 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 503 | BUNDLE_LOADER = "$(TEST_HOST)"; 504 | CODE_SIGN_STYLE = Automatic; 505 | INFOPLIST_FILE = LoadingViewTests/Info.plist; 506 | LD_RUNPATH_SEARCH_PATHS = ( 507 | "$(inherited)", 508 | "@executable_path/Frameworks", 509 | "@loader_path/Frameworks", 510 | ); 511 | PRODUCT_BUNDLE_IDENTIFIER = com.xswift.LoadingViewTests; 512 | PRODUCT_NAME = "$(TARGET_NAME)"; 513 | SWIFT_VERSION = 4.0; 514 | TARGETED_DEVICE_FAMILY = "1,2"; 515 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LoadingView.app/LoadingView"; 516 | }; 517 | name = Debug; 518 | }; 519 | 6E12CC1321A80B0700D9B925 /* Release */ = { 520 | isa = XCBuildConfiguration; 521 | buildSettings = { 522 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 523 | BUNDLE_LOADER = "$(TEST_HOST)"; 524 | CODE_SIGN_STYLE = Automatic; 525 | INFOPLIST_FILE = LoadingViewTests/Info.plist; 526 | LD_RUNPATH_SEARCH_PATHS = ( 527 | "$(inherited)", 528 | "@executable_path/Frameworks", 529 | "@loader_path/Frameworks", 530 | ); 531 | PRODUCT_BUNDLE_IDENTIFIER = com.xswift.LoadingViewTests; 532 | PRODUCT_NAME = "$(TARGET_NAME)"; 533 | SWIFT_VERSION = 4.0; 534 | TARGETED_DEVICE_FAMILY = "1,2"; 535 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LoadingView.app/LoadingView"; 536 | }; 537 | name = Release; 538 | }; 539 | 6E12CC1521A80B0700D9B925 /* Debug */ = { 540 | isa = XCBuildConfiguration; 541 | buildSettings = { 542 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 543 | CODE_SIGN_STYLE = Automatic; 544 | INFOPLIST_FILE = LoadingViewUITests/Info.plist; 545 | LD_RUNPATH_SEARCH_PATHS = ( 546 | "$(inherited)", 547 | "@executable_path/Frameworks", 548 | "@loader_path/Frameworks", 549 | ); 550 | PRODUCT_BUNDLE_IDENTIFIER = com.xswift.LoadingViewUITests; 551 | PRODUCT_NAME = "$(TARGET_NAME)"; 552 | SWIFT_VERSION = 4.0; 553 | TARGETED_DEVICE_FAMILY = "1,2"; 554 | TEST_TARGET_NAME = LoadingView; 555 | }; 556 | name = Debug; 557 | }; 558 | 6E12CC1621A80B0700D9B925 /* Release */ = { 559 | isa = XCBuildConfiguration; 560 | buildSettings = { 561 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 562 | CODE_SIGN_STYLE = Automatic; 563 | INFOPLIST_FILE = LoadingViewUITests/Info.plist; 564 | LD_RUNPATH_SEARCH_PATHS = ( 565 | "$(inherited)", 566 | "@executable_path/Frameworks", 567 | "@loader_path/Frameworks", 568 | ); 569 | PRODUCT_BUNDLE_IDENTIFIER = com.xswift.LoadingViewUITests; 570 | PRODUCT_NAME = "$(TARGET_NAME)"; 571 | SWIFT_VERSION = 4.0; 572 | TARGETED_DEVICE_FAMILY = "1,2"; 573 | TEST_TARGET_NAME = LoadingView; 574 | }; 575 | name = Release; 576 | }; 577 | /* End XCBuildConfiguration section */ 578 | 579 | /* Begin XCConfigurationList section */ 580 | 6E12CBE121A80B0500D9B925 /* Build configuration list for PBXProject "LoadingView" */ = { 581 | isa = XCConfigurationList; 582 | buildConfigurations = ( 583 | 6E12CC0C21A80B0700D9B925 /* Debug */, 584 | 6E12CC0D21A80B0700D9B925 /* Release */, 585 | ); 586 | defaultConfigurationIsVisible = 0; 587 | defaultConfigurationName = Release; 588 | }; 589 | 6E12CC0E21A80B0700D9B925 /* Build configuration list for PBXNativeTarget "LoadingView" */ = { 590 | isa = XCConfigurationList; 591 | buildConfigurations = ( 592 | 6E12CC0F21A80B0700D9B925 /* Debug */, 593 | 6E12CC1021A80B0700D9B925 /* Release */, 594 | ); 595 | defaultConfigurationIsVisible = 0; 596 | defaultConfigurationName = Release; 597 | }; 598 | 6E12CC1121A80B0700D9B925 /* Build configuration list for PBXNativeTarget "LoadingViewTests" */ = { 599 | isa = XCConfigurationList; 600 | buildConfigurations = ( 601 | 6E12CC1221A80B0700D9B925 /* Debug */, 602 | 6E12CC1321A80B0700D9B925 /* Release */, 603 | ); 604 | defaultConfigurationIsVisible = 0; 605 | defaultConfigurationName = Release; 606 | }; 607 | 6E12CC1421A80B0700D9B925 /* Build configuration list for PBXNativeTarget "LoadingViewUITests" */ = { 608 | isa = XCConfigurationList; 609 | buildConfigurations = ( 610 | 6E12CC1521A80B0700D9B925 /* Debug */, 611 | 6E12CC1621A80B0700D9B925 /* Release */, 612 | ); 613 | defaultConfigurationIsVisible = 0; 614 | defaultConfigurationName = Release; 615 | }; 616 | /* End XCConfigurationList section */ 617 | }; 618 | rootObject = 6E12CBDE21A80B0500D9B925 /* Project object */; 619 | } 620 | -------------------------------------------------------------------------------- /LoadingView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LoadingView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LoadingView.xcodeproj/project.xcworkspace/xcuserdata/wangcong.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApterKing/XLoadingView/f85252d129bcfd486339decab3661a4d3f705339/LoadingView.xcodeproj/project.xcworkspace/xcuserdata/wangcong.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /LoadingView.xcodeproj/xcuserdata/wangcong.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | LoadingView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /LoadingView/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // LoadingView 4 | // 5 | // Created by wangcong on 2018/11/23. 6 | // Copyright © 2018年 wangcong. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /LoadingView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /LoadingView/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /LoadingView/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LoadingView/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 | -------------------------------------------------------------------------------- /LoadingView/CGRect+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGRect+Extension.swift 3 | // Swift-X 4 | // 5 | // Created by wangcong on 23/03/2017. 6 | // Copyright © 2017 ApterKing. All rights reserved. 7 | // 8 | 9 | import CoreGraphics 10 | 11 | public extension CGRect { 12 | 13 | public var x: CGFloat { 14 | get { return origin.x } 15 | set { origin.x = newValue } 16 | } 17 | 18 | public var y: CGFloat { 19 | get { return origin.y } 20 | set { origin.y = newValue } 21 | } 22 | 23 | public var width: CGFloat { 24 | get { return size.width } 25 | set { size.width = newValue } 26 | } 27 | 28 | public var height: CGFloat { 29 | get { return size.height } 30 | set { size.height = newValue } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /LoadingView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LoadingView/UIView+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extension.swift 3 | // Swift-X 4 | // 5 | // Created by wangcong on 22/03/2017. 6 | // Copyright © 2017 ApterKing. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // MARK: FirstViewController 12 | public extension UIView { 13 | var firstViewController: UIViewController? { 14 | get { 15 | for view in sequence(first: self.superview, next: { $0?.superview }) { 16 | if let responder = view?.next, responder.isKind(of: UIViewController.self) { 17 | return responder as? UIViewController 18 | } 19 | } 20 | return nil 21 | } 22 | } 23 | } 24 | 25 | // MARK: Frame 26 | public extension UIView { 27 | 28 | public var x: CGFloat { 29 | get { return frame.x } 30 | set { frame.x = newValue } 31 | } 32 | 33 | public var y: CGFloat { 34 | get { return frame.y } 35 | set { frame.y = newValue } 36 | } 37 | 38 | public var width: CGFloat { 39 | get { return frame.width } 40 | set { frame.width = newValue } 41 | } 42 | 43 | public var height: CGFloat { 44 | get { return frame.height } 45 | set { frame.height = newValue } 46 | } 47 | 48 | public var top: CGFloat { 49 | get { return y } 50 | set { y = newValue } 51 | } 52 | 53 | public var left: CGFloat { 54 | get { return x } 55 | set { x = newValue } 56 | } 57 | 58 | public var bottom: CGFloat { 59 | get { return y + height } 60 | set { y = newValue - height } 61 | } 62 | 63 | public var right: CGFloat { 64 | get { return x + width } 65 | set { x = newValue - width } 66 | } 67 | } 68 | 69 | // MARK: Round 70 | public extension UIView { 71 | 72 | public func round(byRoundingCorners: UIRectCorner = UIRectCorner.allCorners, cornerRadi: CGFloat) { 73 | self.round(byRoundingCorners: byRoundingCorners, cornerRadii: CGSize(width: cornerRadi, height: cornerRadi)) 74 | } 75 | 76 | public func round(byRoundingCorners: UIRectCorner = UIRectCorner.allCorners, cornerRadii: CGSize) { 77 | guard let maskLayer = self.layer.mask else { 78 | let rect = self.bounds 79 | let bezierPath = UIBezierPath(roundedRect: rect, 80 | byRoundingCorners: byRoundingCorners, 81 | cornerRadii: cornerRadii) 82 | defer { 83 | bezierPath.close() 84 | } 85 | let shapeLayer = CAShapeLayer() 86 | shapeLayer.path = bezierPath.cgPath 87 | self.layer.mask = shapeLayer 88 | self.layer.masksToBounds = true 89 | return 90 | } 91 | } 92 | } 93 | 94 | // MARK: UIView 快照 95 | public extension UIView { 96 | 97 | public var snapshotImage: UIImage? { 98 | return snapshot() 99 | } 100 | 101 | public func snapshot(rect: CGRect = CGRect.zero, scale: CGFloat = UIScreen.main.scale) -> UIImage? { 102 | var snapRect = rect 103 | if __CGSizeEqualToSize(rect.size, CGSize.zero) { 104 | snapRect = calculateSnapshotRect() 105 | } 106 | UIGraphicsBeginImageContextWithOptions(snapRect.size, false, scale) 107 | defer { 108 | UIGraphicsEndImageContext() 109 | } 110 | self.drawHierarchy(in: snapRect, afterScreenUpdates: false) 111 | return UIGraphicsGetImageFromCurrentImageContext() 112 | } 113 | 114 | // 计算UIView所显示内容Rect 115 | func calculateSnapshotRect() -> CGRect { 116 | var targetRect = self.bounds 117 | if let scrollView = self as? UIScrollView { 118 | let contentInset = scrollView.contentInset 119 | let contentSize = scrollView.contentSize 120 | 121 | targetRect.origin.x = contentInset.left 122 | targetRect.origin.y = contentInset.top 123 | targetRect.size.width = targetRect.size.width - contentInset.left - contentInset.right > contentSize.width ? targetRect.size.width - contentInset.left - contentInset.right : contentSize.width 124 | targetRect.size.height = targetRect.size.height - contentInset.top - contentInset.bottom > contentSize.height ? targetRect.size.height - contentInset.top - contentInset.bottom : contentSize.height 125 | } 126 | return targetRect 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /LoadingView/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // LoadingView 4 | // 5 | // Created by wangcong on 2018/11/23. 6 | // Copyright © 2018年 wangcong. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | 17 | let loading = XLoadingView(frame: UIScreen.main.bounds) 18 | loading.delegate = self 19 | loading.state = .error 20 | view.addSubview(loading) 21 | } 22 | 23 | override func didReceiveMemoryWarning() { 24 | super.didReceiveMemoryWarning() 25 | // Dispose of any resources that can be recreated. 26 | } 27 | 28 | } 29 | 30 | extension ViewController: XLoadingViewDelegate { 31 | 32 | func loadingViewShouldEnableTap(_ loadingView: XLoadingView) -> Bool { 33 | return true 34 | } 35 | 36 | func loadingViewDidTapped(_ loadingView: XLoadingView) { 37 | loadingView.state = .loading 38 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 6) { 39 | loadingView.state = .error 40 | } 41 | } 42 | 43 | func loadingViewPromptImage(_ loadingView: XLoadingView) -> UIImage? { 44 | return UIImage(named: "icon_prompt") 45 | } 46 | 47 | func loadingViewPromptText(_ loadingView: XLoadingView) -> NSAttributedString? { 48 | switch loadingView.state { 49 | case .error: 50 | return NSAttributedString(string: "网络未连接,点击重新加载", attributes: [NSAttributedStringKey.foregroundColor: UIColor.darkGray]) 51 | default: 52 | return nil 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /LoadingView/XLoadingView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XLoadingView.swift 3 | // LegalData 4 | // 5 | // Created by wangcong on 2018/11/23. 6 | // Copyright © 2018年 wangcong. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum XLoadingViewState: String { 12 | case success = "加载成功" 13 | case error = "加载失败,请检查网络" 14 | case loading = "加载中..." 15 | case empty = "暂无数据" 16 | } 17 | 18 | @objc protocol XLoadingViewDelegate: NSObjectProtocol { 19 | 20 | // 点击事件 21 | @objc optional func loadingViewShouldEnableTap(_ loadingView: XLoadingView) -> Bool 22 | @objc optional func loadingViewDidTapped(_ loadingView: XLoadingView) 23 | 24 | // 设置提示 25 | @objc optional func loadingViewPromptImage(_ loadingView: XLoadingView) -> UIImage? 26 | @objc optional func loadingViewPromptText(_ loadingView: XLoadingView) -> NSAttributedString? 27 | 28 | } 29 | 30 | public class XLoadingView: UIView { 31 | 32 | // 加载 33 | private lazy var loadingView: UIView = { 34 | let view = UIView() 35 | view.addSubview(loadingImageView) 36 | view.addSubview(loadingShadowImageView) 37 | return view 38 | }() 39 | private lazy var loadingImageView: UIImageView = { 40 | let imgv = UIImageView() 41 | if let path = Bundle.main.path(forResource: String(format: "icon_loading@%.0fx", UIScreen.main.scale), ofType: ".png") { 42 | imgv.image = UIImage(contentsOfFile: path) 43 | } 44 | imgv.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: 24, height: 24)) 45 | imgv.contentMode = .scaleAspectFit 46 | return imgv 47 | }() 48 | private lazy var loadingShadowImageView: UIImageView = { 49 | let imgv = UIImageView() 50 | if let path = Bundle.main.path(forResource: String(format: "icon_loading_shadow@%.0fx", UIScreen.main.scale), ofType: ".png") { 51 | imgv.image = UIImage(contentsOfFile: path) 52 | } 53 | imgv.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: 30, height: 12)) 54 | imgv.contentMode = .scaleAspectFit 55 | return imgv 56 | }() 57 | 58 | // 提示 59 | private lazy var contentView: UIView = { 60 | let view = UIView() 61 | view.addSubview(promptImageView) 62 | view.addSubview(promptLabel) 63 | return view 64 | }() 65 | private lazy var promptImageView: UIImageView = { 66 | let imgv = UIImageView() 67 | if let path = Bundle.main.path(forResource: String(format: "icon_prompt@%.0fx", UIScreen.main.scale), ofType: ".png") { 68 | imgv.image = UIImage(contentsOfFile: path) 69 | } 70 | imgv.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: 120, height: 120)) 71 | imgv.contentMode = .scaleAspectFit 72 | return imgv 73 | }() 74 | private lazy var promptLabel: UILabel = { 75 | let label = UILabel() 76 | label.textColor = UIColor.darkGray 77 | label.adjustsFontSizeToFitWidth = true 78 | label.textAlignment = .center 79 | return label 80 | }() 81 | 82 | private lazy var timer: CADisplayLink = { 83 | let displayLink = CADisplayLink(target: self, selector: #selector(_animate)) 84 | displayLink.add(to: RunLoop.current, forMode: .defaultRunLoopMode) 85 | if #available(iOS 10, *) { 86 | displayLink.preferredFramesPerSecond = 40 87 | } else { 88 | displayLink.frameInterval = 40 89 | } 90 | displayLink.isPaused = true 91 | return displayLink 92 | }() 93 | private lazy var tapGesture: UITapGestureRecognizer = { 94 | let gesture = UITapGestureRecognizer(target: self, action: #selector(_tapAction)) 95 | return gesture 96 | }() 97 | private var isUp = true 98 | 99 | /// MARK: outter 100 | var delegate: XLoadingViewDelegate? { 101 | didSet { 102 | if delegate?.loadingViewShouldEnableTap?(self) ?? false { 103 | contentView.addGestureRecognizer(tapGesture) 104 | } 105 | } 106 | } 107 | var state: XLoadingViewState = .loading { 108 | didSet { 109 | _resetState() 110 | } 111 | } 112 | 113 | override init(frame: CGRect) { 114 | super.init(frame: frame) 115 | addSubview(contentView) 116 | addSubview(loadingView) 117 | } 118 | 119 | required public init?(coder aDecoder: NSCoder) { 120 | super.init(coder: aDecoder) 121 | } 122 | 123 | override public func layoutSubviews() { 124 | super.layoutSubviews() 125 | contentView.frame = bounds 126 | promptImageView.frame = CGRect(origin: CGPoint(x: (contentView.width - promptImageView.width) / 2.0, y: (contentView.height - promptImageView.height) / 2.0 - 10), size: promptImageView.frame.size) 127 | promptLabel.frame = CGRect(x: 0, y: promptImageView.y + promptImageView.height, width: contentView.width, height: 20) 128 | 129 | loadingView.frame = CGRect(x: (width - 40) / 2.0, y: (height - 80) / 2.0, width: 40, height: 80) 130 | loadingShadowImageView.frame = CGRect(origin: CGPoint(x: (loadingView.width - loadingShadowImageView.width) / 2.0, y: loadingView.height - loadingShadowImageView.height), size: loadingShadowImageView.frame.size) 131 | loadingImageView.frame = CGRect(origin: CGPoint(x: (loadingView.width - loadingImageView.width) / 2.0, y: loadingShadowImageView.y - loadingImageView.height), size: loadingImageView.frame.size) 132 | 133 | _resetState() 134 | } 135 | 136 | deinit { 137 | timer.invalidate() 138 | } 139 | } 140 | 141 | extension XLoadingView { 142 | 143 | @objc private func _resetState() { 144 | if state == .loading { 145 | timer.isPaused = false 146 | contentView.isHidden = true 147 | loadingView.isHidden = false 148 | } else { 149 | timer.isPaused = true 150 | contentView.isHidden = false 151 | loadingView.isHidden = true 152 | } 153 | 154 | if let image = delegate?.loadingViewPromptImage?(self) { 155 | promptImageView.image = image 156 | } else if let path = Bundle.main.path(forResource: String(format: "icon_prompt@%.0fx", UIScreen.main.scale), ofType: ".png") { 157 | promptImageView.image = UIImage(contentsOfFile: path) 158 | } 159 | 160 | if let text = delegate?.loadingViewPromptText?(self) { 161 | promptLabel.attributedText = text 162 | } else { 163 | promptLabel.text = state.rawValue 164 | } 165 | } 166 | 167 | @objc private func _tapAction() { 168 | delegate?.loadingViewDidTapped?(self) 169 | } 170 | 171 | // 这里不使用UIView隐式动画的原因是,多个loadingView时,存在动画中断 172 | @objc private func _animate() { 173 | 174 | var step: CGFloat = 10 175 | if #available(iOS 10, *) { 176 | step = (loadingView.height - loadingShadowImageView.height) / CGFloat(timer.preferredFramesPerSecond) * 1.5 177 | } else { 178 | step = (loadingView.height - loadingShadowImageView.height) / CGFloat(timer.frameInterval) * 1.5 179 | } 180 | 181 | loadingImageView.y = loadingImageView.y + (isUp ? -step : step) 182 | let scale = loadingImageView.y / (loadingView.height - loadingShadowImageView.height - loadingImageView.height) / 2.0 183 | loadingShadowImageView.transform = CGAffineTransform(scaleX: 0.7 + scale, y: 0.7 + scale) 184 | if isUp { 185 | isUp = loadingImageView.y > 0 186 | } else { 187 | isUp = loadingImageView.y > loadingView.height - loadingShadowImageView.height - loadingImageView.height 188 | } 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /LoadingView/icon_loading@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApterKing/XLoadingView/f85252d129bcfd486339decab3661a4d3f705339/LoadingView/icon_loading@2x.png -------------------------------------------------------------------------------- /LoadingView/icon_loading@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApterKing/XLoadingView/f85252d129bcfd486339decab3661a4d3f705339/LoadingView/icon_loading@3x.png -------------------------------------------------------------------------------- /LoadingView/icon_loading_shadow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApterKing/XLoadingView/f85252d129bcfd486339decab3661a4d3f705339/LoadingView/icon_loading_shadow@2x.png -------------------------------------------------------------------------------- /LoadingView/icon_loading_shadow@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApterKing/XLoadingView/f85252d129bcfd486339decab3661a4d3f705339/LoadingView/icon_loading_shadow@3x.png -------------------------------------------------------------------------------- /LoadingView/icon_prompt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApterKing/XLoadingView/f85252d129bcfd486339decab3661a4d3f705339/LoadingView/icon_prompt@2x.png -------------------------------------------------------------------------------- /LoadingView/icon_prompt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApterKing/XLoadingView/f85252d129bcfd486339decab3661a4d3f705339/LoadingView/icon_prompt@3x.png -------------------------------------------------------------------------------- /LoadingViewTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LoadingViewTests/LoadingViewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoadingViewTests.swift 3 | // LoadingViewTests 4 | // 5 | // Created by wangcong on 2018/11/23. 6 | // Copyright © 2018年 wangcong. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LoadingView 11 | 12 | class LoadingViewTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LoadingViewUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LoadingViewUITests/LoadingViewUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoadingViewUITests.swift 3 | // LoadingViewUITests 4 | // 5 | // Created by wangcong on 2018/11/23. 6 | // Copyright © 2018年 wangcong. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class LoadingViewUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XLoadingView 2 | 加载控件 3 | 4 | ![](https://github.com/ApterKing/XLoadingView/blob/master/xloadingview.gif) 5 | -------------------------------------------------------------------------------- /xloadingview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApterKing/XLoadingView/f85252d129bcfd486339decab3661a4d3f705339/xloadingview.gif --------------------------------------------------------------------------------