├── .gitignore ├── Demo ├── PQFCustomLoadersDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── PQFCustomLoadersDemo.xcworkspace │ └── contents.xcworkspacedata ├── PQFCustomLoadersDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── DataViewController.h │ ├── DataViewController.m │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── ModelController.h │ ├── ModelController.m │ ├── RootViewController.h │ ├── RootViewController.m │ └── main.m ├── PQFCustomLoadersDemoTests │ ├── Info.plist │ └── PQFCustomLoadersDemoTests.m └── Podfile ├── Images ├── IBDesignable.png ├── InspectableDemo.png ├── bars.gif ├── bouncing.gif ├── circles.gif ├── demo.png ├── drop.gif └── properties.png ├── InspectableDemo ├── PQFInspectableDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── PQFInspectableDemo.xcworkspace │ └── contents.xcworkspacedata ├── PQFInspectableDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── PQFInspectableDemoTests │ ├── Info.plist │ └── PQFInspectableDemoTests.m └── Podfile ├── LICENSE.md ├── PQFCustomLoaders.podspec ├── PQFCustomLoaders ├── PQFBallDrop.h ├── PQFBallDrop.m ├── PQFBarsInCircle.h ├── PQFBarsInCircle.m ├── PQFBouncingBalls.h ├── PQFBouncingBalls.m ├── PQFCirclesInTriangle.h ├── PQFCirclesInTriangle.m ├── PQFCustomLoaders.h ├── PQFLoader.h └── PQFLoader.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | Pods/ 27 | Podfile.lock 28 | 29 | ### OSX ### 30 | .DS_Store 31 | .AppleDouble 32 | .LSOverride 33 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 08E878130921E3D869926E88 /* Pods_PQFCustomLoadersDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53055DEB7C778B8F136E6201 /* Pods_PQFCustomLoadersDemo.framework */; }; 11 | C1CCD2EF1AB4B1C0005F0B7E /* PQFBarsInCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = C1DA45641AAA3A9100F738C8 /* PQFBarsInCircle.m */; }; 12 | C1D2C16E1A5ADBF4006DF47E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C1D2C16D1A5ADBF4006DF47E /* main.m */; }; 13 | C1D2C1711A5ADBF4006DF47E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C1D2C1701A5ADBF4006DF47E /* AppDelegate.m */; }; 14 | C1D2C1741A5ADBF4006DF47E /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C1D2C1731A5ADBF4006DF47E /* RootViewController.m */; }; 15 | C1D2C1771A5ADBF4006DF47E /* DataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C1D2C1761A5ADBF4006DF47E /* DataViewController.m */; }; 16 | C1D2C17A1A5ADBF4006DF47E /* ModelController.m in Sources */ = {isa = PBXBuildFile; fileRef = C1D2C1791A5ADBF4006DF47E /* ModelController.m */; }; 17 | C1D2C17D1A5ADBF4006DF47E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C1D2C17B1A5ADBF4006DF47E /* Main.storyboard */; }; 18 | C1D2C17F1A5ADBF4006DF47E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C1D2C17E1A5ADBF4006DF47E /* Images.xcassets */; }; 19 | C1D2C1821A5ADBF4006DF47E /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = C1D2C1801A5ADBF4006DF47E /* LaunchScreen.xib */; }; 20 | C1D2C18E1A5ADBF4006DF47E /* PQFCustomLoadersDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C1D2C18D1A5ADBF4006DF47E /* PQFCustomLoadersDemoTests.m */; }; 21 | C1DA455F1AAA39AE00F738C8 /* PQFLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = C1DA455E1AAA39AE00F738C8 /* PQFLoader.m */; }; 22 | C1DA45621AAA3A7A00F738C8 /* PQFBouncingBalls.m in Sources */ = {isa = PBXBuildFile; fileRef = C1DA45611AAA3A7A00F738C8 /* PQFBouncingBalls.m */; }; 23 | C1DA45681AAA3AB200F738C8 /* PQFCirclesInTriangle.m in Sources */ = {isa = PBXBuildFile; fileRef = C1DA45671AAA3AB200F738C8 /* PQFCirclesInTriangle.m */; }; 24 | C1DA456B1AAA3ABE00F738C8 /* PQFBallDrop.m in Sources */ = {isa = PBXBuildFile; fileRef = C1DA456A1AAA3ABE00F738C8 /* PQFBallDrop.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | C1D2C1881A5ADBF4006DF47E /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = C1D2C1601A5ADBF4006DF47E /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = C1D2C1671A5ADBF4006DF47E; 33 | remoteInfo = PQFCustomLoadersDemo; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 42C6E944ED511DA67AFBCEA5 /* Pods-PQFCustomLoadersDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PQFCustomLoadersDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-PQFCustomLoadersDemo/Pods-PQFCustomLoadersDemo.release.xcconfig"; sourceTree = ""; }; 39 | 53055DEB7C778B8F136E6201 /* Pods_PQFCustomLoadersDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PQFCustomLoadersDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 63ABD20E4B8C50AE723C45F7 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 41 | 9FF2D68D2FC22A7CAC7BE99A /* Pods-PQFCustomLoadersDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PQFCustomLoadersDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PQFCustomLoadersDemo/Pods-PQFCustomLoadersDemo.debug.xcconfig"; sourceTree = ""; }; 42 | AB70CEC19EB88C5D490D74B5 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 43 | C1D2C1681A5ADBF4006DF47E /* PQFCustomLoadersDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PQFCustomLoadersDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | C1D2C16C1A5ADBF4006DF47E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | C1D2C16D1A5ADBF4006DF47E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 46 | C1D2C16F1A5ADBF4006DF47E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 47 | C1D2C1701A5ADBF4006DF47E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 48 | C1D2C1721A5ADBF4006DF47E /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; 49 | C1D2C1731A5ADBF4006DF47E /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; 50 | C1D2C1751A5ADBF4006DF47E /* DataViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataViewController.h; sourceTree = ""; }; 51 | C1D2C1761A5ADBF4006DF47E /* DataViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DataViewController.m; sourceTree = ""; }; 52 | C1D2C1781A5ADBF4006DF47E /* ModelController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ModelController.h; sourceTree = ""; }; 53 | C1D2C1791A5ADBF4006DF47E /* ModelController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ModelController.m; sourceTree = ""; }; 54 | C1D2C17C1A5ADBF4006DF47E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | C1D2C17E1A5ADBF4006DF47E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 56 | C1D2C1811A5ADBF4006DF47E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 57 | C1D2C1871A5ADBF4006DF47E /* PQFCustomLoadersDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PQFCustomLoadersDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | C1D2C18C1A5ADBF4006DF47E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | C1D2C18D1A5ADBF4006DF47E /* PQFCustomLoadersDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PQFCustomLoadersDemoTests.m; sourceTree = ""; }; 60 | C1DA455D1AAA39AE00F738C8 /* PQFLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFLoader.h; path = ../../PQFCustomLoaders/PQFLoader.h; sourceTree = ""; }; 61 | C1DA455E1AAA39AE00F738C8 /* PQFLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFLoader.m; path = ../../PQFCustomLoaders/PQFLoader.m; sourceTree = ""; }; 62 | C1DA45601AAA3A7A00F738C8 /* PQFBouncingBalls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFBouncingBalls.h; path = ../../PQFCustomLoaders/PQFBouncingBalls.h; sourceTree = ""; }; 63 | C1DA45611AAA3A7A00F738C8 /* PQFBouncingBalls.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFBouncingBalls.m; path = ../../PQFCustomLoaders/PQFBouncingBalls.m; sourceTree = ""; }; 64 | C1DA45631AAA3A9100F738C8 /* PQFBarsInCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFBarsInCircle.h; path = ../../PQFCustomLoaders/PQFBarsInCircle.h; sourceTree = ""; }; 65 | C1DA45641AAA3A9100F738C8 /* PQFBarsInCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFBarsInCircle.m; path = ../../PQFCustomLoaders/PQFBarsInCircle.m; sourceTree = ""; }; 66 | C1DA45661AAA3AB200F738C8 /* PQFCirclesInTriangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFCirclesInTriangle.h; path = ../../PQFCustomLoaders/PQFCirclesInTriangle.h; sourceTree = ""; }; 67 | C1DA45671AAA3AB200F738C8 /* PQFCirclesInTriangle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFCirclesInTriangle.m; path = ../../PQFCustomLoaders/PQFCirclesInTriangle.m; sourceTree = ""; }; 68 | C1DA45691AAA3ABE00F738C8 /* PQFBallDrop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFBallDrop.h; path = ../../PQFCustomLoaders/PQFBallDrop.h; sourceTree = ""; }; 69 | C1DA456A1AAA3ABE00F738C8 /* PQFBallDrop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFBallDrop.m; path = ../../PQFCustomLoaders/PQFBallDrop.m; sourceTree = ""; }; 70 | C1FFCE4C1A85567800F45B2D /* PQFCustomLoaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFCustomLoaders.h; path = ../../PQFCustomLoaders/PQFCustomLoaders.h; sourceTree = ""; }; 71 | E0F08A3B0A32D39E0205137E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | C1D2C1651A5ADBF4006DF47E /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | 08E878130921E3D869926E88 /* Pods_PQFCustomLoadersDemo.framework in Frameworks */, 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | C1D2C1841A5ADBF4006DF47E /* Frameworks */ = { 84 | isa = PBXFrameworksBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | /* End PBXFrameworksBuildPhase section */ 91 | 92 | /* Begin PBXGroup section */ 93 | 0FDBE4EC1C1960169E9D511E /* Frameworks */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | E0F08A3B0A32D39E0205137E /* libPods.a */, 97 | 53055DEB7C778B8F136E6201 /* Pods_PQFCustomLoadersDemo.framework */, 98 | ); 99 | name = Frameworks; 100 | sourceTree = ""; 101 | }; 102 | 367CF4D44B56DF824008F34F /* Pods */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 63ABD20E4B8C50AE723C45F7 /* Pods.debug.xcconfig */, 106 | AB70CEC19EB88C5D490D74B5 /* Pods.release.xcconfig */, 107 | 9FF2D68D2FC22A7CAC7BE99A /* Pods-PQFCustomLoadersDemo.debug.xcconfig */, 108 | 42C6E944ED511DA67AFBCEA5 /* Pods-PQFCustomLoadersDemo.release.xcconfig */, 109 | ); 110 | name = Pods; 111 | sourceTree = ""; 112 | }; 113 | C1D2C15F1A5ADBF4006DF47E = { 114 | isa = PBXGroup; 115 | children = ( 116 | C1D2C16A1A5ADBF4006DF47E /* PQFCustomLoadersDemo */, 117 | C1D2C18A1A5ADBF4006DF47E /* PQFCustomLoadersDemoTests */, 118 | C1D2C1691A5ADBF4006DF47E /* Products */, 119 | 367CF4D44B56DF824008F34F /* Pods */, 120 | 0FDBE4EC1C1960169E9D511E /* Frameworks */, 121 | ); 122 | sourceTree = ""; 123 | }; 124 | C1D2C1691A5ADBF4006DF47E /* Products */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | C1D2C1681A5ADBF4006DF47E /* PQFCustomLoadersDemo.app */, 128 | C1D2C1871A5ADBF4006DF47E /* PQFCustomLoadersDemoTests.xctest */, 129 | ); 130 | name = Products; 131 | sourceTree = ""; 132 | }; 133 | C1D2C16A1A5ADBF4006DF47E /* PQFCustomLoadersDemo */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | C1D2C16F1A5ADBF4006DF47E /* AppDelegate.h */, 137 | C1D2C1701A5ADBF4006DF47E /* AppDelegate.m */, 138 | C1D2C1A31A5AE53B006DF47E /* PageBased Controller */, 139 | C1D2C1A21A5AE529006DF47E /* View */, 140 | C1D2C1A41A5AE5C3006DF47E /* PQFCustomLoaders */, 141 | C1D2C16B1A5ADBF4006DF47E /* Supporting Files */, 142 | C1D2C17E1A5ADBF4006DF47E /* Images.xcassets */, 143 | ); 144 | path = PQFCustomLoadersDemo; 145 | sourceTree = ""; 146 | }; 147 | C1D2C16B1A5ADBF4006DF47E /* Supporting Files */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | C1D2C16C1A5ADBF4006DF47E /* Info.plist */, 151 | C1D2C16D1A5ADBF4006DF47E /* main.m */, 152 | ); 153 | name = "Supporting Files"; 154 | sourceTree = ""; 155 | }; 156 | C1D2C18A1A5ADBF4006DF47E /* PQFCustomLoadersDemoTests */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | C1D2C18D1A5ADBF4006DF47E /* PQFCustomLoadersDemoTests.m */, 160 | C1D2C18B1A5ADBF4006DF47E /* Supporting Files */, 161 | ); 162 | path = PQFCustomLoadersDemoTests; 163 | sourceTree = ""; 164 | }; 165 | C1D2C18B1A5ADBF4006DF47E /* Supporting Files */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | C1D2C18C1A5ADBF4006DF47E /* Info.plist */, 169 | ); 170 | name = "Supporting Files"; 171 | sourceTree = ""; 172 | }; 173 | C1D2C1A21A5AE529006DF47E /* View */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | C1D2C17B1A5ADBF4006DF47E /* Main.storyboard */, 177 | C1D2C1801A5ADBF4006DF47E /* LaunchScreen.xib */, 178 | ); 179 | name = View; 180 | sourceTree = ""; 181 | }; 182 | C1D2C1A31A5AE53B006DF47E /* PageBased Controller */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | C1D2C1721A5ADBF4006DF47E /* RootViewController.h */, 186 | C1D2C1731A5ADBF4006DF47E /* RootViewController.m */, 187 | C1D2C1751A5ADBF4006DF47E /* DataViewController.h */, 188 | C1D2C1761A5ADBF4006DF47E /* DataViewController.m */, 189 | C1D2C1781A5ADBF4006DF47E /* ModelController.h */, 190 | C1D2C1791A5ADBF4006DF47E /* ModelController.m */, 191 | ); 192 | name = "PageBased Controller"; 193 | sourceTree = ""; 194 | }; 195 | C1D2C1A41A5AE5C3006DF47E /* PQFCustomLoaders */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | C1FFCE4C1A85567800F45B2D /* PQFCustomLoaders.h */, 199 | C1DA455D1AAA39AE00F738C8 /* PQFLoader.h */, 200 | C1DA455E1AAA39AE00F738C8 /* PQFLoader.m */, 201 | C1DA45601AAA3A7A00F738C8 /* PQFBouncingBalls.h */, 202 | C1DA45611AAA3A7A00F738C8 /* PQFBouncingBalls.m */, 203 | C1DA45631AAA3A9100F738C8 /* PQFBarsInCircle.h */, 204 | C1DA45641AAA3A9100F738C8 /* PQFBarsInCircle.m */, 205 | C1DA45661AAA3AB200F738C8 /* PQFCirclesInTriangle.h */, 206 | C1DA45671AAA3AB200F738C8 /* PQFCirclesInTriangle.m */, 207 | C1DA45691AAA3ABE00F738C8 /* PQFBallDrop.h */, 208 | C1DA456A1AAA3ABE00F738C8 /* PQFBallDrop.m */, 209 | ); 210 | name = PQFCustomLoaders; 211 | sourceTree = ""; 212 | }; 213 | /* End PBXGroup section */ 214 | 215 | /* Begin PBXNativeTarget section */ 216 | C1D2C1671A5ADBF4006DF47E /* PQFCustomLoadersDemo */ = { 217 | isa = PBXNativeTarget; 218 | buildConfigurationList = C1D2C1911A5ADBF4006DF47E /* Build configuration list for PBXNativeTarget "PQFCustomLoadersDemo" */; 219 | buildPhases = ( 220 | 0BD6C784D2EC15B18BA8938B /* [CP] Check Pods Manifest.lock */, 221 | C1D2C1641A5ADBF4006DF47E /* Sources */, 222 | C1D2C1651A5ADBF4006DF47E /* Frameworks */, 223 | C1D2C1661A5ADBF4006DF47E /* Resources */, 224 | 80A89D36836650CA4F9E8016 /* [CP] Copy Pods Resources */, 225 | B409052F1B29F5C570F32C9B /* [CP] Embed Pods Frameworks */, 226 | ); 227 | buildRules = ( 228 | ); 229 | dependencies = ( 230 | ); 231 | name = PQFCustomLoadersDemo; 232 | productName = PQFCustomLoadersDemo; 233 | productReference = C1D2C1681A5ADBF4006DF47E /* PQFCustomLoadersDemo.app */; 234 | productType = "com.apple.product-type.application"; 235 | }; 236 | C1D2C1861A5ADBF4006DF47E /* PQFCustomLoadersDemoTests */ = { 237 | isa = PBXNativeTarget; 238 | buildConfigurationList = C1D2C1941A5ADBF4006DF47E /* Build configuration list for PBXNativeTarget "PQFCustomLoadersDemoTests" */; 239 | buildPhases = ( 240 | C1D2C1831A5ADBF4006DF47E /* Sources */, 241 | C1D2C1841A5ADBF4006DF47E /* Frameworks */, 242 | C1D2C1851A5ADBF4006DF47E /* Resources */, 243 | ); 244 | buildRules = ( 245 | ); 246 | dependencies = ( 247 | C1D2C1891A5ADBF4006DF47E /* PBXTargetDependency */, 248 | ); 249 | name = PQFCustomLoadersDemoTests; 250 | productName = PQFCustomLoadersDemoTests; 251 | productReference = C1D2C1871A5ADBF4006DF47E /* PQFCustomLoadersDemoTests.xctest */; 252 | productType = "com.apple.product-type.bundle.unit-test"; 253 | }; 254 | /* End PBXNativeTarget section */ 255 | 256 | /* Begin PBXProject section */ 257 | C1D2C1601A5ADBF4006DF47E /* Project object */ = { 258 | isa = PBXProject; 259 | attributes = { 260 | LastUpgradeCheck = 0610; 261 | ORGANIZATIONNAME = "Pol Quintana"; 262 | TargetAttributes = { 263 | C1D2C1671A5ADBF4006DF47E = { 264 | CreatedOnToolsVersion = 6.1.1; 265 | }; 266 | C1D2C1861A5ADBF4006DF47E = { 267 | CreatedOnToolsVersion = 6.1.1; 268 | TestTargetID = C1D2C1671A5ADBF4006DF47E; 269 | }; 270 | }; 271 | }; 272 | buildConfigurationList = C1D2C1631A5ADBF4006DF47E /* Build configuration list for PBXProject "PQFCustomLoadersDemo" */; 273 | compatibilityVersion = "Xcode 3.2"; 274 | developmentRegion = English; 275 | hasScannedForEncodings = 0; 276 | knownRegions = ( 277 | en, 278 | Base, 279 | ); 280 | mainGroup = C1D2C15F1A5ADBF4006DF47E; 281 | productRefGroup = C1D2C1691A5ADBF4006DF47E /* Products */; 282 | projectDirPath = ""; 283 | projectRoot = ""; 284 | targets = ( 285 | C1D2C1671A5ADBF4006DF47E /* PQFCustomLoadersDemo */, 286 | C1D2C1861A5ADBF4006DF47E /* PQFCustomLoadersDemoTests */, 287 | ); 288 | }; 289 | /* End PBXProject section */ 290 | 291 | /* Begin PBXResourcesBuildPhase section */ 292 | C1D2C1661A5ADBF4006DF47E /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | C1D2C17D1A5ADBF4006DF47E /* Main.storyboard in Resources */, 297 | C1D2C1821A5ADBF4006DF47E /* LaunchScreen.xib in Resources */, 298 | C1D2C17F1A5ADBF4006DF47E /* Images.xcassets in Resources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | C1D2C1851A5ADBF4006DF47E /* Resources */ = { 303 | isa = PBXResourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | /* End PBXResourcesBuildPhase section */ 310 | 311 | /* Begin PBXShellScriptBuildPhase section */ 312 | 0BD6C784D2EC15B18BA8938B /* [CP] Check Pods Manifest.lock */ = { 313 | isa = PBXShellScriptBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | ); 317 | inputPaths = ( 318 | ); 319 | name = "[CP] Check Pods Manifest.lock"; 320 | outputPaths = ( 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | shellPath = /bin/sh; 324 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 325 | showEnvVarsInLog = 0; 326 | }; 327 | 80A89D36836650CA4F9E8016 /* [CP] Copy Pods Resources */ = { 328 | isa = PBXShellScriptBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | ); 332 | inputPaths = ( 333 | ); 334 | name = "[CP] Copy Pods Resources"; 335 | outputPaths = ( 336 | ); 337 | runOnlyForDeploymentPostprocessing = 0; 338 | shellPath = /bin/sh; 339 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PQFCustomLoadersDemo/Pods-PQFCustomLoadersDemo-resources.sh\"\n"; 340 | showEnvVarsInLog = 0; 341 | }; 342 | B409052F1B29F5C570F32C9B /* [CP] Embed Pods Frameworks */ = { 343 | isa = PBXShellScriptBuildPhase; 344 | buildActionMask = 2147483647; 345 | files = ( 346 | ); 347 | inputPaths = ( 348 | ); 349 | name = "[CP] Embed Pods Frameworks"; 350 | outputPaths = ( 351 | ); 352 | runOnlyForDeploymentPostprocessing = 0; 353 | shellPath = /bin/sh; 354 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PQFCustomLoadersDemo/Pods-PQFCustomLoadersDemo-frameworks.sh\"\n"; 355 | showEnvVarsInLog = 0; 356 | }; 357 | /* End PBXShellScriptBuildPhase section */ 358 | 359 | /* Begin PBXSourcesBuildPhase section */ 360 | C1D2C1641A5ADBF4006DF47E /* Sources */ = { 361 | isa = PBXSourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | C1D2C1771A5ADBF4006DF47E /* DataViewController.m in Sources */, 365 | C1DA45681AAA3AB200F738C8 /* PQFCirclesInTriangle.m in Sources */, 366 | C1D2C1711A5ADBF4006DF47E /* AppDelegate.m in Sources */, 367 | C1D2C17A1A5ADBF4006DF47E /* ModelController.m in Sources */, 368 | C1DA45621AAA3A7A00F738C8 /* PQFBouncingBalls.m in Sources */, 369 | C1D2C16E1A5ADBF4006DF47E /* main.m in Sources */, 370 | C1D2C1741A5ADBF4006DF47E /* RootViewController.m in Sources */, 371 | C1DA455F1AAA39AE00F738C8 /* PQFLoader.m in Sources */, 372 | C1CCD2EF1AB4B1C0005F0B7E /* PQFBarsInCircle.m in Sources */, 373 | C1DA456B1AAA3ABE00F738C8 /* PQFBallDrop.m in Sources */, 374 | ); 375 | runOnlyForDeploymentPostprocessing = 0; 376 | }; 377 | C1D2C1831A5ADBF4006DF47E /* Sources */ = { 378 | isa = PBXSourcesBuildPhase; 379 | buildActionMask = 2147483647; 380 | files = ( 381 | C1D2C18E1A5ADBF4006DF47E /* PQFCustomLoadersDemoTests.m in Sources */, 382 | ); 383 | runOnlyForDeploymentPostprocessing = 0; 384 | }; 385 | /* End PBXSourcesBuildPhase section */ 386 | 387 | /* Begin PBXTargetDependency section */ 388 | C1D2C1891A5ADBF4006DF47E /* PBXTargetDependency */ = { 389 | isa = PBXTargetDependency; 390 | target = C1D2C1671A5ADBF4006DF47E /* PQFCustomLoadersDemo */; 391 | targetProxy = C1D2C1881A5ADBF4006DF47E /* PBXContainerItemProxy */; 392 | }; 393 | /* End PBXTargetDependency section */ 394 | 395 | /* Begin PBXVariantGroup section */ 396 | C1D2C17B1A5ADBF4006DF47E /* Main.storyboard */ = { 397 | isa = PBXVariantGroup; 398 | children = ( 399 | C1D2C17C1A5ADBF4006DF47E /* Base */, 400 | ); 401 | name = Main.storyboard; 402 | sourceTree = ""; 403 | }; 404 | C1D2C1801A5ADBF4006DF47E /* LaunchScreen.xib */ = { 405 | isa = PBXVariantGroup; 406 | children = ( 407 | C1D2C1811A5ADBF4006DF47E /* Base */, 408 | ); 409 | name = LaunchScreen.xib; 410 | sourceTree = ""; 411 | }; 412 | /* End PBXVariantGroup section */ 413 | 414 | /* Begin XCBuildConfiguration section */ 415 | C1D2C18F1A5ADBF4006DF47E /* Debug */ = { 416 | isa = XCBuildConfiguration; 417 | buildSettings = { 418 | ALWAYS_SEARCH_USER_PATHS = NO; 419 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 420 | CLANG_CXX_LIBRARY = "libc++"; 421 | CLANG_ENABLE_MODULES = YES; 422 | CLANG_ENABLE_OBJC_ARC = YES; 423 | CLANG_WARN_BOOL_CONVERSION = YES; 424 | CLANG_WARN_CONSTANT_CONVERSION = YES; 425 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 426 | CLANG_WARN_EMPTY_BODY = YES; 427 | CLANG_WARN_ENUM_CONVERSION = YES; 428 | CLANG_WARN_INT_CONVERSION = YES; 429 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 430 | CLANG_WARN_UNREACHABLE_CODE = YES; 431 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 432 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 433 | COPY_PHASE_STRIP = NO; 434 | ENABLE_STRICT_OBJC_MSGSEND = YES; 435 | GCC_C_LANGUAGE_STANDARD = gnu99; 436 | GCC_DYNAMIC_NO_PIC = NO; 437 | GCC_OPTIMIZATION_LEVEL = 0; 438 | GCC_PREPROCESSOR_DEFINITIONS = ( 439 | "DEBUG=1", 440 | "$(inherited)", 441 | ); 442 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 443 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 444 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 445 | GCC_WARN_UNDECLARED_SELECTOR = YES; 446 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 447 | GCC_WARN_UNUSED_FUNCTION = YES; 448 | GCC_WARN_UNUSED_VARIABLE = YES; 449 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 450 | MTL_ENABLE_DEBUG_INFO = YES; 451 | ONLY_ACTIVE_ARCH = YES; 452 | SDKROOT = iphoneos; 453 | TARGETED_DEVICE_FAMILY = "1,2"; 454 | }; 455 | name = Debug; 456 | }; 457 | C1D2C1901A5ADBF4006DF47E /* Release */ = { 458 | isa = XCBuildConfiguration; 459 | buildSettings = { 460 | ALWAYS_SEARCH_USER_PATHS = NO; 461 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 462 | CLANG_CXX_LIBRARY = "libc++"; 463 | CLANG_ENABLE_MODULES = YES; 464 | CLANG_ENABLE_OBJC_ARC = YES; 465 | CLANG_WARN_BOOL_CONVERSION = YES; 466 | CLANG_WARN_CONSTANT_CONVERSION = YES; 467 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 468 | CLANG_WARN_EMPTY_BODY = YES; 469 | CLANG_WARN_ENUM_CONVERSION = YES; 470 | CLANG_WARN_INT_CONVERSION = YES; 471 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 472 | CLANG_WARN_UNREACHABLE_CODE = YES; 473 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 474 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 475 | COPY_PHASE_STRIP = YES; 476 | ENABLE_NS_ASSERTIONS = NO; 477 | ENABLE_STRICT_OBJC_MSGSEND = YES; 478 | GCC_C_LANGUAGE_STANDARD = gnu99; 479 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 480 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 481 | GCC_WARN_UNDECLARED_SELECTOR = YES; 482 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 483 | GCC_WARN_UNUSED_FUNCTION = YES; 484 | GCC_WARN_UNUSED_VARIABLE = YES; 485 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 486 | MTL_ENABLE_DEBUG_INFO = NO; 487 | SDKROOT = iphoneos; 488 | TARGETED_DEVICE_FAMILY = "1,2"; 489 | VALIDATE_PRODUCT = YES; 490 | }; 491 | name = Release; 492 | }; 493 | C1D2C1921A5ADBF4006DF47E /* Debug */ = { 494 | isa = XCBuildConfiguration; 495 | baseConfigurationReference = 9FF2D68D2FC22A7CAC7BE99A /* Pods-PQFCustomLoadersDemo.debug.xcconfig */; 496 | buildSettings = { 497 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 498 | INFOPLIST_FILE = PQFCustomLoadersDemo/Info.plist; 499 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | }; 502 | name = Debug; 503 | }; 504 | C1D2C1931A5ADBF4006DF47E /* Release */ = { 505 | isa = XCBuildConfiguration; 506 | baseConfigurationReference = 42C6E944ED511DA67AFBCEA5 /* Pods-PQFCustomLoadersDemo.release.xcconfig */; 507 | buildSettings = { 508 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 509 | INFOPLIST_FILE = PQFCustomLoadersDemo/Info.plist; 510 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 511 | PRODUCT_NAME = "$(TARGET_NAME)"; 512 | }; 513 | name = Release; 514 | }; 515 | C1D2C1951A5ADBF4006DF47E /* Debug */ = { 516 | isa = XCBuildConfiguration; 517 | buildSettings = { 518 | BUNDLE_LOADER = "$(TEST_HOST)"; 519 | FRAMEWORK_SEARCH_PATHS = ( 520 | "$(SDKROOT)/Developer/Library/Frameworks", 521 | "$(inherited)", 522 | ); 523 | GCC_PREPROCESSOR_DEFINITIONS = ( 524 | "DEBUG=1", 525 | "$(inherited)", 526 | ); 527 | INFOPLIST_FILE = PQFCustomLoadersDemoTests/Info.plist; 528 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 529 | PRODUCT_NAME = "$(TARGET_NAME)"; 530 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PQFCustomLoadersDemo.app/PQFCustomLoadersDemo"; 531 | }; 532 | name = Debug; 533 | }; 534 | C1D2C1961A5ADBF4006DF47E /* Release */ = { 535 | isa = XCBuildConfiguration; 536 | buildSettings = { 537 | BUNDLE_LOADER = "$(TEST_HOST)"; 538 | FRAMEWORK_SEARCH_PATHS = ( 539 | "$(SDKROOT)/Developer/Library/Frameworks", 540 | "$(inherited)", 541 | ); 542 | INFOPLIST_FILE = PQFCustomLoadersDemoTests/Info.plist; 543 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 544 | PRODUCT_NAME = "$(TARGET_NAME)"; 545 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PQFCustomLoadersDemo.app/PQFCustomLoadersDemo"; 546 | }; 547 | name = Release; 548 | }; 549 | /* End XCBuildConfiguration section */ 550 | 551 | /* Begin XCConfigurationList section */ 552 | C1D2C1631A5ADBF4006DF47E /* Build configuration list for PBXProject "PQFCustomLoadersDemo" */ = { 553 | isa = XCConfigurationList; 554 | buildConfigurations = ( 555 | C1D2C18F1A5ADBF4006DF47E /* Debug */, 556 | C1D2C1901A5ADBF4006DF47E /* Release */, 557 | ); 558 | defaultConfigurationIsVisible = 0; 559 | defaultConfigurationName = Release; 560 | }; 561 | C1D2C1911A5ADBF4006DF47E /* Build configuration list for PBXNativeTarget "PQFCustomLoadersDemo" */ = { 562 | isa = XCConfigurationList; 563 | buildConfigurations = ( 564 | C1D2C1921A5ADBF4006DF47E /* Debug */, 565 | C1D2C1931A5ADBF4006DF47E /* Release */, 566 | ); 567 | defaultConfigurationIsVisible = 0; 568 | defaultConfigurationName = Release; 569 | }; 570 | C1D2C1941A5ADBF4006DF47E /* Build configuration list for PBXNativeTarget "PQFCustomLoadersDemoTests" */ = { 571 | isa = XCConfigurationList; 572 | buildConfigurations = ( 573 | C1D2C1951A5ADBF4006DF47E /* Debug */, 574 | C1D2C1961A5ADBF4006DF47E /* Release */, 575 | ); 576 | defaultConfigurationIsVisible = 0; 577 | defaultConfigurationName = Release; 578 | }; 579 | /* End XCConfigurationList section */ 580 | }; 581 | rootObject = C1D2C1601A5ADBF4006DF47E /* Project object */; 582 | } 583 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/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 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 53 | 73 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/DataViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DataViewController.h 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PQFCustomLoaders.h" 11 | 12 | @interface DataViewController : UIViewController 13 | 14 | @property (strong, nonatomic) IBOutlet UILabel *dataLabel; 15 | @property (nonatomic) NSUInteger pageIndex; 16 | @property (nonatomic) id loader; 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/DataViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DataViewController.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "DataViewController.h" 10 | 11 | static const CGFloat kButtonCornerRadius = 4; 12 | #define kButtonColor [UIColor colorWithWhite:0.2 alpha:0.5] 13 | 14 | @interface DataViewController () { 15 | BOOL _showing; 16 | BOOL _showingModal; 17 | BOOL _showingText; 18 | } 19 | @property (weak, nonatomic) IBOutlet UIButton *presentModallyOutlet; 20 | @property (weak, nonatomic) IBOutlet UIButton *showTextOutlet; 21 | @property (nonatomic, strong) UIButton *modalButton; 22 | @end 23 | 24 | @implementation DataViewController 25 | 26 | - (void)viewDidLoad 27 | { 28 | [super viewDidLoad]; 29 | self.presentModallyOutlet.layer.cornerRadius = kButtonCornerRadius; 30 | self.presentModallyOutlet.layer.backgroundColor = kButtonColor.CGColor; 31 | self.showTextOutlet.layer.cornerRadius = kButtonCornerRadius; 32 | self.showTextOutlet.layer.backgroundColor = kButtonColor.CGColor; 33 | } 34 | 35 | - (void)viewDidAppear:(BOOL)animated 36 | { 37 | [super viewDidAppear:animated]; 38 | self.dataLabel.text = NSStringFromClass([self.loader class]); 39 | if (_showing) return; 40 | [self.loader showLoader]; 41 | _showing = YES; 42 | _showingText = NO; 43 | [self.showTextOutlet setTitle:@"Show Text" forState:UIControlStateNormal]; 44 | } 45 | 46 | - (void)viewDidDisappear:(BOOL)animated 47 | { 48 | [super viewDidDisappear:animated]; 49 | [self.loader removeLoader]; 50 | self.loader = nil; 51 | _showing = NO; 52 | _showingModal = NO; 53 | } 54 | 55 | - (void)viewWillDisappear:(BOOL)animated 56 | { 57 | [super viewWillDisappear:animated]; 58 | if (!_showingModal) return; 59 | [self presentLoaderModally:self]; 60 | } 61 | 62 | 63 | #pragma mark - User interaction 64 | 65 | - (IBAction)presentLoaderModally:(id)sender 66 | { 67 | self.showTextOutlet.enabled = _showingModal; 68 | if (!_showingModal) { 69 | [self.loader removeLoader]; 70 | self.loader = [[self loaderClass] createModalLoader]; 71 | [self.loader showLoader]; 72 | [[[UIApplication sharedApplication].delegate window] addSubview:self.modalButton]; 73 | _showingModal = YES; 74 | } 75 | else { 76 | [self.loader removeLoader]; 77 | self.loader = nil; 78 | [self.modalButton removeFromSuperview]; 79 | [self.loader showLoader]; 80 | _showingModal = NO; 81 | } 82 | } 83 | 84 | - (IBAction)showText:(id)sender { 85 | NSString *title; 86 | [self.loader removeLoader]; 87 | self.loader = nil; 88 | if (!_showingText) { 89 | title = @"Hide Text"; 90 | [self.loader label].text = @"Your description here plus mas mas mas"; 91 | [self.loader setBackgroundColor:[UIColor colorWithWhite:0.2 alpha:0.6]]; 92 | } 93 | else { 94 | title = @"Show Text"; 95 | [self.loader label].text = nil; 96 | } 97 | _showingText = !_showingText; 98 | [self.showTextOutlet setTitle:title forState:UIControlStateNormal]; 99 | [self.loader showLoader]; 100 | } 101 | 102 | 103 | #pragma mark - Helper 104 | 105 | - (Class)loaderClass 106 | { 107 | switch (self.pageIndex) { 108 | case 0: 109 | return [PQFBouncingBalls class]; 110 | break; 111 | case 1: 112 | return [PQFBarsInCircle class]; 113 | break; 114 | case 2: 115 | return [PQFCirclesInTriangle class]; 116 | break; 117 | case 3: 118 | return [PQFBallDrop class]; 119 | break; 120 | default: 121 | return nil; 122 | break; 123 | } 124 | } 125 | 126 | 127 | #pragma mark - Lazy 128 | 129 | - (id)loader 130 | { 131 | if (!_loader) { 132 | _loader = [[self loaderClass] createLoaderOnView:self.view]; 133 | } 134 | return _loader; 135 | } 136 | - (UIButton *)modalButton 137 | { 138 | if (!_modalButton) { 139 | _modalButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 180, 40)]; 140 | _modalButton.layer.backgroundColor = [UIColor colorWithWhite:0.2 alpha:1.0].CGColor; 141 | _modalButton.layer.cornerRadius = 4; 142 | [_modalButton setTitle:@"Hide Modal" forState:UIControlStateNormal]; 143 | _modalButton.center = self.presentModallyOutlet.center; 144 | [_modalButton addTarget:self action:@selector(presentLoaderModally:) forControlEvents:UIControlEventTouchUpInside]; 145 | } 146 | 147 | return _modalButton; 148 | } 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.polquintana.$(PRODUCT_NAME:rfc1034identifier) 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 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/ModelController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModelController.h 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DataViewController; 12 | 13 | @interface ModelController : NSObject 14 | 15 | - (DataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard; 16 | - (NSUInteger)indexOfViewController:(DataViewController *)viewController; 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/ModelController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModelController.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "ModelController.h" 10 | #import "DataViewController.h" 11 | 12 | #import "PQFCustomLoaders.h" 13 | 14 | @interface ModelController () 15 | 16 | @property (readonly, strong, nonatomic) NSArray *pageData; 17 | 18 | @end 19 | 20 | @implementation ModelController 21 | 22 | - (instancetype)init { 23 | self = [super init]; 24 | if (self) { 25 | _pageData = @[@"PQFBouncingBalls", @"PQFBarsInCircle", @"PQFCirclesInTriangle", @"PQFBallDrop"]; 26 | } 27 | return self; 28 | } 29 | 30 | - (DataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard { 31 | if (([self.pageData count] == 0) || (index >= [self.pageData count])) { 32 | return nil; 33 | } 34 | 35 | DataViewController *dataViewController = [storyboard instantiateViewControllerWithIdentifier:@"DataViewController"]; 36 | dataViewController.pageIndex = index; 37 | 38 | return dataViewController; 39 | } 40 | 41 | - (NSUInteger)indexOfViewController:(DataViewController *)viewController { 42 | 43 | NSString *loaderClass = NSStringFromClass([viewController.loader class]); 44 | 45 | return [self.pageData indexOfObject:loaderClass]; 46 | } 47 | 48 | #pragma mark - Page View Controller Data Source 49 | 50 | - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController 51 | { 52 | NSUInteger index = [self indexOfViewController:(DataViewController *)viewController]; 53 | if (index == NSNotFound) { 54 | return nil; 55 | } 56 | else if (index == 0) { 57 | return [self viewControllerAtIndex:[self.pageData count] - 1 storyboard:viewController.storyboard]; 58 | } 59 | 60 | index--; 61 | 62 | return [self viewControllerAtIndex:index storyboard:viewController.storyboard]; 63 | } 64 | 65 | - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController 66 | { 67 | NSUInteger index = [self indexOfViewController:(DataViewController *)viewController]; 68 | if (index == NSNotFound) { 69 | return nil; 70 | } 71 | 72 | index++; 73 | if (index == [self.pageData count]) { 74 | return [self viewControllerAtIndex:0 storyboard:viewController.storyboard]; 75 | } 76 | return [self viewControllerAtIndex:index storyboard:viewController.storyboard]; 77 | } 78 | 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/RootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RootViewController : UIViewController 12 | 13 | @property (strong, nonatomic) UIPageViewController *pageViewController; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/RootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "RootViewController.h" 10 | #import "ModelController.h" 11 | #import "DataViewController.h" 12 | 13 | @interface RootViewController () 14 | 15 | @property (readonly, strong, nonatomic) ModelController *modelController; 16 | @end 17 | 18 | @implementation RootViewController 19 | 20 | @synthesize modelController = _modelController; 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil]; 26 | self.pageViewController.delegate = self; 27 | 28 | DataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard]; 29 | NSArray *viewControllers = @[startingViewController]; 30 | [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil]; 31 | 32 | self.pageViewController.dataSource = self.modelController; 33 | 34 | [self addChildViewController:self.pageViewController]; 35 | [self.view addSubview:self.pageViewController.view]; 36 | 37 | CGRect pageViewRect = self.view.bounds; 38 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 39 | pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0); 40 | } 41 | self.pageViewController.view.frame = pageViewRect; 42 | 43 | [self.pageViewController didMoveToParentViewController:self]; 44 | 45 | self.view.gestureRecognizers = self.pageViewController.gestureRecognizers; 46 | } 47 | 48 | - (void)didReceiveMemoryWarning { 49 | [super didReceiveMemoryWarning]; 50 | } 51 | 52 | - (ModelController *)modelController { 53 | if (!_modelController) { 54 | _modelController = [[ModelController alloc] init]; 55 | } 56 | return _modelController; 57 | } 58 | 59 | #pragma mark - UIPageViewController delegate methods 60 | 61 | - (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation { 62 | if (UIInterfaceOrientationIsPortrait(orientation) || ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)) { 63 | 64 | UIViewController *currentViewController = self.pageViewController.viewControllers[0]; 65 | NSArray *viewControllers = @[currentViewController]; 66 | [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; 67 | 68 | self.pageViewController.doubleSided = NO; 69 | return UIPageViewControllerSpineLocationMin; 70 | } 71 | 72 | DataViewController *currentViewController = self.pageViewController.viewControllers[0]; 73 | NSArray *viewControllers = nil; 74 | 75 | NSUInteger indexOfCurrentViewController = [self.modelController indexOfViewController:currentViewController]; 76 | if (indexOfCurrentViewController == 0 || indexOfCurrentViewController % 2 == 0) { 77 | UIViewController *nextViewController = [self.modelController pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController]; 78 | 79 | viewControllers = @[currentViewController, nextViewController]; 80 | } else { 81 | UIViewController *previousViewController = [self.modelController pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController]; 82 | viewControllers = @[previousViewController, currentViewController]; 83 | } 84 | [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil]; 85 | 86 | 87 | return UIPageViewControllerSpineLocationMid; 88 | } 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.polquintana.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Demo/PQFCustomLoadersDemoTests/PQFCustomLoadersDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // PQFCustomLoadersDemoTests.m 3 | // PQFCustomLoadersDemoTests 4 | // 5 | // Created by Pol Quintana on 5/1/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface PQFCustomLoadersDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation PQFCustomLoadersDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Demo/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, "8.0" 2 | use_frameworks! 3 | 4 | target :PQFCustomLoadersDemo do 5 | pod 'UIColor+FlatColors' 6 | pod 'pop', '~> 1.0' 7 | end 8 | -------------------------------------------------------------------------------- /Images/IBDesignable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polqf/PQFCustomLoaders/bfbf6a7b560db89da480a1e9e4d3a4fa66cec300/Images/IBDesignable.png -------------------------------------------------------------------------------- /Images/InspectableDemo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polqf/PQFCustomLoaders/bfbf6a7b560db89da480a1e9e4d3a4fa66cec300/Images/InspectableDemo.png -------------------------------------------------------------------------------- /Images/bars.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polqf/PQFCustomLoaders/bfbf6a7b560db89da480a1e9e4d3a4fa66cec300/Images/bars.gif -------------------------------------------------------------------------------- /Images/bouncing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polqf/PQFCustomLoaders/bfbf6a7b560db89da480a1e9e4d3a4fa66cec300/Images/bouncing.gif -------------------------------------------------------------------------------- /Images/circles.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polqf/PQFCustomLoaders/bfbf6a7b560db89da480a1e9e4d3a4fa66cec300/Images/circles.gif -------------------------------------------------------------------------------- /Images/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polqf/PQFCustomLoaders/bfbf6a7b560db89da480a1e9e4d3a4fa66cec300/Images/demo.png -------------------------------------------------------------------------------- /Images/drop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polqf/PQFCustomLoaders/bfbf6a7b560db89da480a1e9e4d3a4fa66cec300/Images/drop.gif -------------------------------------------------------------------------------- /Images/properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polqf/PQFCustomLoaders/bfbf6a7b560db89da480a1e9e4d3a4fa66cec300/Images/properties.png -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BAEA71077014879097B7C6D5 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C096F3ACC7BA64B8CC53A3D /* libPods.a */; }; 11 | C15DF4D21B1237F300C12B16 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF4D11B1237F300C12B16 /* main.m */; }; 12 | C15DF4D51B1237F300C12B16 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF4D41B1237F300C12B16 /* AppDelegate.m */; }; 13 | C15DF4D81B1237F300C12B16 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF4D71B1237F300C12B16 /* ViewController.m */; }; 14 | C15DF4DB1B1237F300C12B16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C15DF4D91B1237F300C12B16 /* Main.storyboard */; }; 15 | C15DF4DD1B1237F300C12B16 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C15DF4DC1B1237F300C12B16 /* Images.xcassets */; }; 16 | C15DF4E01B1237F300C12B16 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = C15DF4DE1B1237F300C12B16 /* LaunchScreen.xib */; }; 17 | C15DF4EC1B1237F300C12B16 /* PQFInspectableDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF4EB1B1237F300C12B16 /* PQFInspectableDemoTests.m */; }; 18 | C15DF5011B12397D00C12B16 /* PQFBallDrop.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF4F71B12397D00C12B16 /* PQFBallDrop.m */; }; 19 | C15DF5021B12397D00C12B16 /* PQFBarsInCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF4F91B12397D00C12B16 /* PQFBarsInCircle.m */; }; 20 | C15DF5031B12397D00C12B16 /* PQFBouncingBalls.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF4FB1B12397D00C12B16 /* PQFBouncingBalls.m */; }; 21 | C15DF5041B12397D00C12B16 /* PQFCirclesInTriangle.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF4FD1B12397D00C12B16 /* PQFCirclesInTriangle.m */; }; 22 | C15DF5051B12397D00C12B16 /* PQFLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = C15DF5001B12397D00C12B16 /* PQFLoader.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | C15DF4E61B1237F300C12B16 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = C15DF4C41B1237F300C12B16 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = C15DF4CB1B1237F300C12B16; 31 | remoteInfo = PQFInspectableDemo; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 14FE7A1C6391C8955571834D /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 37 | 7C096F3ACC7BA64B8CC53A3D /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | C15DF4CC1B1237F300C12B16 /* PQFInspectableDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PQFInspectableDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | C15DF4D01B1237F300C12B16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | C15DF4D11B1237F300C12B16 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 41 | C15DF4D31B1237F300C12B16 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 42 | C15DF4D41B1237F300C12B16 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 43 | C15DF4D61B1237F300C12B16 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 44 | C15DF4D71B1237F300C12B16 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 45 | C15DF4DA1B1237F300C12B16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46 | C15DF4DC1B1237F300C12B16 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 47 | C15DF4DF1B1237F300C12B16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 48 | C15DF4E51B1237F300C12B16 /* PQFInspectableDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PQFInspectableDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | C15DF4EA1B1237F300C12B16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | C15DF4EB1B1237F300C12B16 /* PQFInspectableDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PQFInspectableDemoTests.m; sourceTree = ""; }; 51 | C15DF4F61B12397D00C12B16 /* PQFBallDrop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFBallDrop.h; path = ../../PQFCustomLoaders/PQFBallDrop.h; sourceTree = ""; }; 52 | C15DF4F71B12397D00C12B16 /* PQFBallDrop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFBallDrop.m; path = ../../PQFCustomLoaders/PQFBallDrop.m; sourceTree = ""; }; 53 | C15DF4F81B12397D00C12B16 /* PQFBarsInCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFBarsInCircle.h; path = ../../PQFCustomLoaders/PQFBarsInCircle.h; sourceTree = ""; }; 54 | C15DF4F91B12397D00C12B16 /* PQFBarsInCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFBarsInCircle.m; path = ../../PQFCustomLoaders/PQFBarsInCircle.m; sourceTree = ""; }; 55 | C15DF4FA1B12397D00C12B16 /* PQFBouncingBalls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFBouncingBalls.h; path = ../../PQFCustomLoaders/PQFBouncingBalls.h; sourceTree = ""; }; 56 | C15DF4FB1B12397D00C12B16 /* PQFBouncingBalls.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFBouncingBalls.m; path = ../../PQFCustomLoaders/PQFBouncingBalls.m; sourceTree = ""; }; 57 | C15DF4FC1B12397D00C12B16 /* PQFCirclesInTriangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFCirclesInTriangle.h; path = ../../PQFCustomLoaders/PQFCirclesInTriangle.h; sourceTree = ""; }; 58 | C15DF4FD1B12397D00C12B16 /* PQFCirclesInTriangle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFCirclesInTriangle.m; path = ../../PQFCustomLoaders/PQFCirclesInTriangle.m; sourceTree = ""; }; 59 | C15DF4FE1B12397D00C12B16 /* PQFCustomLoaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFCustomLoaders.h; path = ../../PQFCustomLoaders/PQFCustomLoaders.h; sourceTree = ""; }; 60 | C15DF4FF1B12397D00C12B16 /* PQFLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PQFLoader.h; path = ../../PQFCustomLoaders/PQFLoader.h; sourceTree = ""; }; 61 | C15DF5001B12397D00C12B16 /* PQFLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PQFLoader.m; path = ../../PQFCustomLoaders/PQFLoader.m; sourceTree = ""; }; 62 | F0DFE28D8C2ED7ECDE436A80 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | C15DF4C91B1237F300C12B16 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | BAEA71077014879097B7C6D5 /* libPods.a in Frameworks */, 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | C15DF4E21B1237F300C12B16 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 5B4ACA6D80C26327EF7D1387 /* Pods */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | F0DFE28D8C2ED7ECDE436A80 /* Pods.debug.xcconfig */, 88 | 14FE7A1C6391C8955571834D /* Pods.release.xcconfig */, 89 | ); 90 | name = Pods; 91 | sourceTree = ""; 92 | }; 93 | C15DF4C31B1237F300C12B16 = { 94 | isa = PBXGroup; 95 | children = ( 96 | C15DF4CE1B1237F300C12B16 /* PQFInspectableDemo */, 97 | C15DF4E81B1237F300C12B16 /* PQFInspectableDemoTests */, 98 | C15DF4CD1B1237F300C12B16 /* Products */, 99 | 5B4ACA6D80C26327EF7D1387 /* Pods */, 100 | F84E3F5AA3344350733336E9 /* Frameworks */, 101 | ); 102 | sourceTree = ""; 103 | }; 104 | C15DF4CD1B1237F300C12B16 /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | C15DF4CC1B1237F300C12B16 /* PQFInspectableDemo.app */, 108 | C15DF4E51B1237F300C12B16 /* PQFInspectableDemoTests.xctest */, 109 | ); 110 | name = Products; 111 | sourceTree = ""; 112 | }; 113 | C15DF4CE1B1237F300C12B16 /* PQFInspectableDemo */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | C15DF4D31B1237F300C12B16 /* AppDelegate.h */, 117 | C15DF4D41B1237F300C12B16 /* AppDelegate.m */, 118 | C15DF4D61B1237F300C12B16 /* ViewController.h */, 119 | C15DF4D71B1237F300C12B16 /* ViewController.m */, 120 | C15DF4D91B1237F300C12B16 /* Main.storyboard */, 121 | C15DF4DC1B1237F300C12B16 /* Images.xcassets */, 122 | C15DF4DE1B1237F300C12B16 /* LaunchScreen.xib */, 123 | C15DF4F51B12396300C12B16 /* PQFCustomLoaders */, 124 | C15DF4CF1B1237F300C12B16 /* Supporting Files */, 125 | ); 126 | path = PQFInspectableDemo; 127 | sourceTree = ""; 128 | }; 129 | C15DF4CF1B1237F300C12B16 /* Supporting Files */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | C15DF4D01B1237F300C12B16 /* Info.plist */, 133 | C15DF4D11B1237F300C12B16 /* main.m */, 134 | ); 135 | name = "Supporting Files"; 136 | sourceTree = ""; 137 | }; 138 | C15DF4E81B1237F300C12B16 /* PQFInspectableDemoTests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | C15DF4EB1B1237F300C12B16 /* PQFInspectableDemoTests.m */, 142 | C15DF4E91B1237F300C12B16 /* Supporting Files */, 143 | ); 144 | path = PQFInspectableDemoTests; 145 | sourceTree = ""; 146 | }; 147 | C15DF4E91B1237F300C12B16 /* Supporting Files */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | C15DF4EA1B1237F300C12B16 /* Info.plist */, 151 | ); 152 | name = "Supporting Files"; 153 | sourceTree = ""; 154 | }; 155 | C15DF4F51B12396300C12B16 /* PQFCustomLoaders */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | C15DF4FE1B12397D00C12B16 /* PQFCustomLoaders.h */, 159 | C15DF4FF1B12397D00C12B16 /* PQFLoader.h */, 160 | C15DF5001B12397D00C12B16 /* PQFLoader.m */, 161 | C15DF4FA1B12397D00C12B16 /* PQFBouncingBalls.h */, 162 | C15DF4FB1B12397D00C12B16 /* PQFBouncingBalls.m */, 163 | C15DF4F81B12397D00C12B16 /* PQFBarsInCircle.h */, 164 | C15DF4F91B12397D00C12B16 /* PQFBarsInCircle.m */, 165 | C15DF4FC1B12397D00C12B16 /* PQFCirclesInTriangle.h */, 166 | C15DF4FD1B12397D00C12B16 /* PQFCirclesInTriangle.m */, 167 | C15DF4F61B12397D00C12B16 /* PQFBallDrop.h */, 168 | C15DF4F71B12397D00C12B16 /* PQFBallDrop.m */, 169 | ); 170 | name = PQFCustomLoaders; 171 | sourceTree = ""; 172 | }; 173 | F84E3F5AA3344350733336E9 /* Frameworks */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | 7C096F3ACC7BA64B8CC53A3D /* libPods.a */, 177 | ); 178 | name = Frameworks; 179 | sourceTree = ""; 180 | }; 181 | /* End PBXGroup section */ 182 | 183 | /* Begin PBXNativeTarget section */ 184 | C15DF4CB1B1237F300C12B16 /* PQFInspectableDemo */ = { 185 | isa = PBXNativeTarget; 186 | buildConfigurationList = C15DF4EF1B1237F300C12B16 /* Build configuration list for PBXNativeTarget "PQFInspectableDemo" */; 187 | buildPhases = ( 188 | 96AA296DC2B93C3F50573BC0 /* Check Pods Manifest.lock */, 189 | C15DF4C81B1237F300C12B16 /* Sources */, 190 | C15DF4C91B1237F300C12B16 /* Frameworks */, 191 | C15DF4CA1B1237F300C12B16 /* Resources */, 192 | 4D23956A73A20D3B5FCE26D6 /* Copy Pods Resources */, 193 | ); 194 | buildRules = ( 195 | ); 196 | dependencies = ( 197 | ); 198 | name = PQFInspectableDemo; 199 | productName = PQFInspectableDemo; 200 | productReference = C15DF4CC1B1237F300C12B16 /* PQFInspectableDemo.app */; 201 | productType = "com.apple.product-type.application"; 202 | }; 203 | C15DF4E41B1237F300C12B16 /* PQFInspectableDemoTests */ = { 204 | isa = PBXNativeTarget; 205 | buildConfigurationList = C15DF4F21B1237F300C12B16 /* Build configuration list for PBXNativeTarget "PQFInspectableDemoTests" */; 206 | buildPhases = ( 207 | C15DF4E11B1237F300C12B16 /* Sources */, 208 | C15DF4E21B1237F300C12B16 /* Frameworks */, 209 | C15DF4E31B1237F300C12B16 /* Resources */, 210 | ); 211 | buildRules = ( 212 | ); 213 | dependencies = ( 214 | C15DF4E71B1237F300C12B16 /* PBXTargetDependency */, 215 | ); 216 | name = PQFInspectableDemoTests; 217 | productName = PQFInspectableDemoTests; 218 | productReference = C15DF4E51B1237F300C12B16 /* PQFInspectableDemoTests.xctest */; 219 | productType = "com.apple.product-type.bundle.unit-test"; 220 | }; 221 | /* End PBXNativeTarget section */ 222 | 223 | /* Begin PBXProject section */ 224 | C15DF4C41B1237F300C12B16 /* Project object */ = { 225 | isa = PBXProject; 226 | attributes = { 227 | LastUpgradeCheck = 0630; 228 | ORGANIZATIONNAME = "Pol Quintana"; 229 | TargetAttributes = { 230 | C15DF4CB1B1237F300C12B16 = { 231 | CreatedOnToolsVersion = 6.3.1; 232 | }; 233 | C15DF4E41B1237F300C12B16 = { 234 | CreatedOnToolsVersion = 6.3.1; 235 | TestTargetID = C15DF4CB1B1237F300C12B16; 236 | }; 237 | }; 238 | }; 239 | buildConfigurationList = C15DF4C71B1237F300C12B16 /* Build configuration list for PBXProject "PQFInspectableDemo" */; 240 | compatibilityVersion = "Xcode 3.2"; 241 | developmentRegion = English; 242 | hasScannedForEncodings = 0; 243 | knownRegions = ( 244 | en, 245 | Base, 246 | ); 247 | mainGroup = C15DF4C31B1237F300C12B16; 248 | productRefGroup = C15DF4CD1B1237F300C12B16 /* Products */; 249 | projectDirPath = ""; 250 | projectRoot = ""; 251 | targets = ( 252 | C15DF4CB1B1237F300C12B16 /* PQFInspectableDemo */, 253 | C15DF4E41B1237F300C12B16 /* PQFInspectableDemoTests */, 254 | ); 255 | }; 256 | /* End PBXProject section */ 257 | 258 | /* Begin PBXResourcesBuildPhase section */ 259 | C15DF4CA1B1237F300C12B16 /* Resources */ = { 260 | isa = PBXResourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | C15DF4DB1B1237F300C12B16 /* Main.storyboard in Resources */, 264 | C15DF4E01B1237F300C12B16 /* LaunchScreen.xib in Resources */, 265 | C15DF4DD1B1237F300C12B16 /* Images.xcassets in Resources */, 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | C15DF4E31B1237F300C12B16 /* Resources */ = { 270 | isa = PBXResourcesBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXResourcesBuildPhase section */ 277 | 278 | /* Begin PBXShellScriptBuildPhase section */ 279 | 4D23956A73A20D3B5FCE26D6 /* Copy Pods Resources */ = { 280 | isa = PBXShellScriptBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | ); 284 | inputPaths = ( 285 | ); 286 | name = "Copy Pods Resources"; 287 | outputPaths = ( 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | shellPath = /bin/sh; 291 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 292 | showEnvVarsInLog = 0; 293 | }; 294 | 96AA296DC2B93C3F50573BC0 /* Check Pods Manifest.lock */ = { 295 | isa = PBXShellScriptBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | ); 299 | inputPaths = ( 300 | ); 301 | name = "Check Pods Manifest.lock"; 302 | outputPaths = ( 303 | ); 304 | runOnlyForDeploymentPostprocessing = 0; 305 | shellPath = /bin/sh; 306 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 307 | showEnvVarsInLog = 0; 308 | }; 309 | /* End PBXShellScriptBuildPhase section */ 310 | 311 | /* Begin PBXSourcesBuildPhase section */ 312 | C15DF4C81B1237F300C12B16 /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | C15DF4D81B1237F300C12B16 /* ViewController.m in Sources */, 317 | C15DF5021B12397D00C12B16 /* PQFBarsInCircle.m in Sources */, 318 | C15DF4D51B1237F300C12B16 /* AppDelegate.m in Sources */, 319 | C15DF4D21B1237F300C12B16 /* main.m in Sources */, 320 | C15DF5051B12397D00C12B16 /* PQFLoader.m in Sources */, 321 | C15DF5041B12397D00C12B16 /* PQFCirclesInTriangle.m in Sources */, 322 | C15DF5011B12397D00C12B16 /* PQFBallDrop.m in Sources */, 323 | C15DF5031B12397D00C12B16 /* PQFBouncingBalls.m in Sources */, 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | }; 327 | C15DF4E11B1237F300C12B16 /* Sources */ = { 328 | isa = PBXSourcesBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | C15DF4EC1B1237F300C12B16 /* PQFInspectableDemoTests.m in Sources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | /* End PBXSourcesBuildPhase section */ 336 | 337 | /* Begin PBXTargetDependency section */ 338 | C15DF4E71B1237F300C12B16 /* PBXTargetDependency */ = { 339 | isa = PBXTargetDependency; 340 | target = C15DF4CB1B1237F300C12B16 /* PQFInspectableDemo */; 341 | targetProxy = C15DF4E61B1237F300C12B16 /* PBXContainerItemProxy */; 342 | }; 343 | /* End PBXTargetDependency section */ 344 | 345 | /* Begin PBXVariantGroup section */ 346 | C15DF4D91B1237F300C12B16 /* Main.storyboard */ = { 347 | isa = PBXVariantGroup; 348 | children = ( 349 | C15DF4DA1B1237F300C12B16 /* Base */, 350 | ); 351 | name = Main.storyboard; 352 | sourceTree = ""; 353 | }; 354 | C15DF4DE1B1237F300C12B16 /* LaunchScreen.xib */ = { 355 | isa = PBXVariantGroup; 356 | children = ( 357 | C15DF4DF1B1237F300C12B16 /* Base */, 358 | ); 359 | name = LaunchScreen.xib; 360 | sourceTree = ""; 361 | }; 362 | /* End PBXVariantGroup section */ 363 | 364 | /* Begin XCBuildConfiguration section */ 365 | C15DF4ED1B1237F300C12B16 /* Debug */ = { 366 | isa = XCBuildConfiguration; 367 | buildSettings = { 368 | ALWAYS_SEARCH_USER_PATHS = NO; 369 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 370 | CLANG_CXX_LIBRARY = "libc++"; 371 | CLANG_ENABLE_MODULES = YES; 372 | CLANG_ENABLE_OBJC_ARC = YES; 373 | CLANG_WARN_BOOL_CONVERSION = YES; 374 | CLANG_WARN_CONSTANT_CONVERSION = YES; 375 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 376 | CLANG_WARN_EMPTY_BODY = YES; 377 | CLANG_WARN_ENUM_CONVERSION = YES; 378 | CLANG_WARN_INT_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_UNREACHABLE_CODE = YES; 381 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 382 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 383 | COPY_PHASE_STRIP = NO; 384 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 385 | ENABLE_STRICT_OBJC_MSGSEND = YES; 386 | GCC_C_LANGUAGE_STANDARD = gnu99; 387 | GCC_DYNAMIC_NO_PIC = NO; 388 | GCC_NO_COMMON_BLOCKS = YES; 389 | GCC_OPTIMIZATION_LEVEL = 0; 390 | GCC_PREPROCESSOR_DEFINITIONS = ( 391 | "DEBUG=1", 392 | "$(inherited)", 393 | ); 394 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 402 | MTL_ENABLE_DEBUG_INFO = YES; 403 | ONLY_ACTIVE_ARCH = YES; 404 | SDKROOT = iphoneos; 405 | TARGETED_DEVICE_FAMILY = "1,2"; 406 | }; 407 | name = Debug; 408 | }; 409 | C15DF4EE1B1237F300C12B16 /* Release */ = { 410 | isa = XCBuildConfiguration; 411 | buildSettings = { 412 | ALWAYS_SEARCH_USER_PATHS = NO; 413 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 414 | CLANG_CXX_LIBRARY = "libc++"; 415 | CLANG_ENABLE_MODULES = YES; 416 | CLANG_ENABLE_OBJC_ARC = YES; 417 | CLANG_WARN_BOOL_CONVERSION = YES; 418 | CLANG_WARN_CONSTANT_CONVERSION = YES; 419 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 420 | CLANG_WARN_EMPTY_BODY = YES; 421 | CLANG_WARN_ENUM_CONVERSION = YES; 422 | CLANG_WARN_INT_CONVERSION = YES; 423 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 424 | CLANG_WARN_UNREACHABLE_CODE = YES; 425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 427 | COPY_PHASE_STRIP = NO; 428 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 429 | ENABLE_NS_ASSERTIONS = NO; 430 | ENABLE_STRICT_OBJC_MSGSEND = YES; 431 | GCC_C_LANGUAGE_STANDARD = gnu99; 432 | GCC_NO_COMMON_BLOCKS = YES; 433 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 434 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 435 | GCC_WARN_UNDECLARED_SELECTOR = YES; 436 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 437 | GCC_WARN_UNUSED_FUNCTION = YES; 438 | GCC_WARN_UNUSED_VARIABLE = YES; 439 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 440 | MTL_ENABLE_DEBUG_INFO = NO; 441 | SDKROOT = iphoneos; 442 | TARGETED_DEVICE_FAMILY = "1,2"; 443 | VALIDATE_PRODUCT = YES; 444 | }; 445 | name = Release; 446 | }; 447 | C15DF4F01B1237F300C12B16 /* Debug */ = { 448 | isa = XCBuildConfiguration; 449 | baseConfigurationReference = F0DFE28D8C2ED7ECDE436A80 /* Pods.debug.xcconfig */; 450 | buildSettings = { 451 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 452 | INFOPLIST_FILE = PQFInspectableDemo/Info.plist; 453 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 454 | PRODUCT_NAME = "$(TARGET_NAME)"; 455 | }; 456 | name = Debug; 457 | }; 458 | C15DF4F11B1237F300C12B16 /* Release */ = { 459 | isa = XCBuildConfiguration; 460 | baseConfigurationReference = 14FE7A1C6391C8955571834D /* Pods.release.xcconfig */; 461 | buildSettings = { 462 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 463 | INFOPLIST_FILE = PQFInspectableDemo/Info.plist; 464 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 465 | PRODUCT_NAME = "$(TARGET_NAME)"; 466 | }; 467 | name = Release; 468 | }; 469 | C15DF4F31B1237F300C12B16 /* Debug */ = { 470 | isa = XCBuildConfiguration; 471 | buildSettings = { 472 | BUNDLE_LOADER = "$(TEST_HOST)"; 473 | FRAMEWORK_SEARCH_PATHS = ( 474 | "$(SDKROOT)/Developer/Library/Frameworks", 475 | "$(inherited)", 476 | ); 477 | GCC_PREPROCESSOR_DEFINITIONS = ( 478 | "DEBUG=1", 479 | "$(inherited)", 480 | ); 481 | INFOPLIST_FILE = PQFInspectableDemoTests/Info.plist; 482 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 483 | PRODUCT_NAME = "$(TARGET_NAME)"; 484 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PQFInspectableDemo.app/PQFInspectableDemo"; 485 | }; 486 | name = Debug; 487 | }; 488 | C15DF4F41B1237F300C12B16 /* Release */ = { 489 | isa = XCBuildConfiguration; 490 | buildSettings = { 491 | BUNDLE_LOADER = "$(TEST_HOST)"; 492 | FRAMEWORK_SEARCH_PATHS = ( 493 | "$(SDKROOT)/Developer/Library/Frameworks", 494 | "$(inherited)", 495 | ); 496 | INFOPLIST_FILE = PQFInspectableDemoTests/Info.plist; 497 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 498 | PRODUCT_NAME = "$(TARGET_NAME)"; 499 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PQFInspectableDemo.app/PQFInspectableDemo"; 500 | }; 501 | name = Release; 502 | }; 503 | /* End XCBuildConfiguration section */ 504 | 505 | /* Begin XCConfigurationList section */ 506 | C15DF4C71B1237F300C12B16 /* Build configuration list for PBXProject "PQFInspectableDemo" */ = { 507 | isa = XCConfigurationList; 508 | buildConfigurations = ( 509 | C15DF4ED1B1237F300C12B16 /* Debug */, 510 | C15DF4EE1B1237F300C12B16 /* Release */, 511 | ); 512 | defaultConfigurationIsVisible = 0; 513 | defaultConfigurationName = Release; 514 | }; 515 | C15DF4EF1B1237F300C12B16 /* Build configuration list for PBXNativeTarget "PQFInspectableDemo" */ = { 516 | isa = XCConfigurationList; 517 | buildConfigurations = ( 518 | C15DF4F01B1237F300C12B16 /* Debug */, 519 | C15DF4F11B1237F300C12B16 /* Release */, 520 | ); 521 | defaultConfigurationIsVisible = 0; 522 | defaultConfigurationName = Release; 523 | }; 524 | C15DF4F21B1237F300C12B16 /* Build configuration list for PBXNativeTarget "PQFInspectableDemoTests" */ = { 525 | isa = XCConfigurationList; 526 | buildConfigurations = ( 527 | C15DF4F31B1237F300C12B16 /* Debug */, 528 | C15DF4F41B1237F300C12B16 /* Release */, 529 | ); 530 | defaultConfigurationIsVisible = 0; 531 | defaultConfigurationName = Release; 532 | }; 533 | /* End XCConfigurationList section */ 534 | }; 535 | rootObject = C15DF4C41B1237F300C12B16 /* Project object */; 536 | } 537 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PQFInspectableDemo 4 | // 5 | // Created by Pol Quintana on 24/5/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PQFInspectableDemo 4 | // 5 | // Created by Pol Quintana on 24/5/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/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 | 31 | 32 | 33 | 34 | 35 | 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 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.polquintana.$(PRODUCT_NAME:rfc1034identifier) 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 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // PQFInspectableDemo 4 | // 5 | // Created by Pol Quintana on 24/5/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // PQFInspectableDemo 4 | // 5 | // Created by Pol Quintana on 24/5/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "PQFCustomLoaders.h" 11 | 12 | @interface ViewController () 13 | @property (weak, nonatomic) IBOutlet PQFBouncingBalls *bouncingBallsLoader; 14 | @property (weak, nonatomic) IBOutlet PQFBarsInCircle *barsInCircleLoader; 15 | @property (weak, nonatomic) IBOutlet PQFCirclesInTriangle *circlesInTriangleLoader; 16 | @property (weak, nonatomic) IBOutlet PQFBallDrop *ballDropLoader; 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | // Do any additional setup after loading the view, typically from a nib. 24 | [self.bouncingBallsLoader showLoader]; 25 | [self.barsInCircleLoader showLoader]; 26 | [self.circlesInTriangleLoader showLoader]; 27 | [self.ballDropLoader showLoader]; 28 | } 29 | 30 | - (void)didReceiveMemoryWarning { 31 | [super didReceiveMemoryWarning]; 32 | // Dispose of any resources that can be recreated. 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PQFInspectableDemo 4 | // 5 | // Created by Pol Quintana on 24/5/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.polquintana.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /InspectableDemo/PQFInspectableDemoTests/PQFInspectableDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // PQFInspectableDemoTests.m 3 | // PQFInspectableDemoTests 4 | // 5 | // Created by Pol Quintana on 24/5/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface PQFInspectableDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation PQFInspectableDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /InspectableDemo/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, "8.0" 2 | 3 | pod 'UIColor+FlatColors' 4 | pod 'pop', '~> 1.0' -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) {{{year}}} {{{fullname}}} 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PQFCustomLoaders.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "PQFCustomLoaders" 3 | s.version = "1.1.0" 4 | s.summary = "Collection of Custom Loaders highly customizable." 5 | s.homepage = "https://github.com/poolqf/PQFCustomLoaders" 6 | s.license = 'MIT' 7 | s.author = "Pol Quintana" 8 | s.source = { :git => "https://github.com/poolqf/PQFCustomLoaders.git", :tag => "1.1.0" } 9 | s.platform = :ios, '7.0' 10 | s.source_files = 'PQFCustomLoaders' 11 | s.frameworks = 'UIKit' 12 | s.requires_arc = true 13 | s.social_media_url = 'https://twitter.com/poolqf' 14 | s.dependency 'UIColor+FlatColors' 15 | s.dependency 'pop', '~> 1.0' 16 | end 17 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFBallDrop.h: -------------------------------------------------------------------------------- 1 | // 2 | // PQFBallDrop.h 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PQFLoader.h" 11 | 12 | IB_DESIGNABLE 13 | @interface PQFBallDrop : PQFLoader 14 | /** Text label of the Loader. Hidden if text is nil */ 15 | @property (nonatomic, strong) IBInspectable UILabel *label; 16 | /** Corner radius of the Loader background */ 17 | @property (nonatomic, assign) IBInspectable CGFloat cornerRadius; 18 | /** Color of the Loader */ 19 | @property (nonatomic, strong) IBInspectable UIColor *loaderColor; 20 | /** Alpha of the loader */ 21 | @property (nonatomic, assign) IBInspectable CGFloat loaderAlpha; 22 | /** Duration of each animation */ 23 | @property (nonatomic, assign) IBInspectable CGFloat duration; 24 | /** Size of the label text */ 25 | @property (nonatomic, assign) IBInspectable CGFloat fontSize; 26 | /** Maximum diameter of the circles */ 27 | @property (nonatomic, assign) IBInspectable CGFloat maxDiam; 28 | /** Delay between the animations */ 29 | @property (nonatomic, assign) IBInspectable CGFloat delay; 30 | /** Ball added size when droping */ 31 | @property (nonatomic, assign) IBInspectable CGFloat amountZoom; 32 | /** Alpha of the hole view */ 33 | @property (nonatomic, assign) IBInspectable CGFloat alpha; 34 | @end 35 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFBallDrop.m: -------------------------------------------------------------------------------- 1 | // 2 | // PQFBallDrop.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "PQFBallDrop.h" 10 | #import 11 | #import 12 | 13 | @interface PQFBallDrop () 14 | @property (nonatomic, strong) UIView *loaderView; 15 | @property (nonatomic, strong) UIView *fallingBall; 16 | @property (nonatomic, strong) UIView *mainBall; 17 | @property (nonatomic, strong) UIDynamicAnimator *mainAnimator; 18 | @property (nonatomic, strong) UIGravityBehavior *gravityBehaviour; 19 | @property (nonatomic, strong) UICollisionBehavior *collisionBehaviour; 20 | @property (nonatomic) BOOL restart; 21 | @property (nonatomic) BOOL animate; 22 | @property (nonatomic) CGFloat rectSize; 23 | @end 24 | 25 | @implementation PQFBallDrop 26 | 27 | 28 | #pragma mark - IB_DESIGNABLE 29 | 30 | - (id)initWithCoder:(NSCoder *)aDecoder 31 | { 32 | self = [super initWithCoder:aDecoder]; 33 | if (self) { 34 | [self initialSetupWithView:nil]; 35 | } 36 | return self; 37 | } 38 | 39 | 40 | + (instancetype)showLoaderOnView:(UIView *)view 41 | { 42 | PQFBallDrop *loader = [self createLoaderOnView:view]; 43 | [loader showLoader]; 44 | return loader; 45 | } 46 | 47 | + (instancetype)createLoaderOnView:(UIView *)view 48 | { 49 | if (!view) view = [[UIApplication sharedApplication].delegate window]; 50 | PQFBallDrop *loader = [PQFBallDrop new]; 51 | [loader initialSetupWithView:view]; 52 | return loader; 53 | } 54 | 55 | - (void)showLoader 56 | { 57 | [self performSelector:@selector(startShowingLoader) withObject:nil afterDelay:0]; 58 | } 59 | 60 | - (void)startShowingLoader 61 | { 62 | self.hidden = NO; 63 | self.animate = YES; 64 | [self generateLoader]; 65 | [self startAnimating]; 66 | } 67 | 68 | - (void)hideLoader 69 | { 70 | self.hidden = YES; 71 | self.animate = NO; 72 | } 73 | 74 | - (void)removeLoader 75 | { 76 | [self hideLoader]; 77 | [self removeFromSuperview]; 78 | } 79 | 80 | 81 | #pragma mark - Prepare loader 82 | 83 | - (void)initialSetupWithView:(UIView *)view 84 | { 85 | //Setting up frame 86 | self.frame = view.frame; 87 | self.center = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)); 88 | 89 | //If it is modal, background for the loader 90 | if ([view isKindOfClass:[UIWindow class]]) { 91 | UIView *bgView = [[UIView alloc] initWithFrame:view.bounds]; 92 | bgView.backgroundColor = [UIColor colorWithWhite:0.2 alpha:0.6]; 93 | [self addSubview:bgView]; 94 | } 95 | 96 | //Add loader to its superview 97 | [view addSubview:self]; 98 | 99 | [self.loaderView addSubview:self.label]; 100 | 101 | //Initial Values 102 | [self defaultValues]; 103 | 104 | //Initially hidden 105 | self.hidden = YES; 106 | } 107 | 108 | - (void)defaultValues 109 | { 110 | [super setBackgroundColor:[UIColor clearColor]]; 111 | self.restart = YES; 112 | self.loaderAlpha = 1.0; 113 | self.loaderColor = [UIColor flatTurquoiseColor]; 114 | self.maxDiam = 50; 115 | self.amountZoom = 5; 116 | self.delay = 1.7; 117 | self.duration = 2.0; 118 | self.fontSize = 14.0; 119 | self.rectSize = self.maxDiam; 120 | } 121 | 122 | 123 | #pragma mark - Before showing 124 | 125 | 126 | - (void)generateLoader 127 | { 128 | self.loaderView.frame = CGRectMake(0, 0, self.frame.size.width, self.rectSize + 30); 129 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 130 | self.loaderView.layer.cornerRadius = self.cornerRadius; 131 | [self layoutBalls]; 132 | if (self.label.text) [self layoutLabel]; 133 | } 134 | 135 | - (void)layoutBalls 136 | { 137 | self.fallingBall.frame = CGRectMake(self.loaderView.frame.size.width/2 - 5, 0, 10, 10); 138 | self.fallingBall.layer.cornerRadius = 5; 139 | self.fallingBall.center = CGPointMake(CGRectGetWidth(self.loaderView.frame)/2, 0); 140 | self.mainBall.frame = CGRectMake(0, 0, 0, 0); 141 | self.mainBall.layer.cornerRadius = 0; 142 | self.mainBall.center = CGPointMake(CGRectGetWidth(self.loaderView.frame)/2 , CGRectGetHeight(self.loaderView.frame)/2); 143 | } 144 | 145 | - (void)layoutLabel 146 | { 147 | self.label.textAlignment = NSTextAlignmentCenter; 148 | self.label.numberOfLines = 3; 149 | self.label.textColor = [UIColor whiteColor]; 150 | self.label.font = [UIFont systemFontOfSize:self.fontSize]; 151 | 152 | CGFloat xCenter = self.center.x; 153 | CGFloat yCenter = self.center.y; 154 | self.mainBall.center = CGPointMake(self.mainBall.center.x, self.mainBall.center.y + 10); 155 | 156 | self.loaderView.frame = CGRectMake(self.loaderView.frame.origin.x, self.loaderView.frame.origin.y, self.loaderView.frame.size.width, self.loaderView.frame.size.height + 10 + self.fontSize*2+10 ); 157 | 158 | self.frame = CGRectMake(0, 0, self.frame.size.width, self.loaderView.frame.size.height + 10); 159 | self.center = CGPointMake(xCenter, yCenter); 160 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 161 | 162 | CGFloat xPoint = CGRectGetWidth(self.loaderView.frame)/2; 163 | CGFloat yPoint = CGRectGetHeight(self.loaderView.frame) - self.fontSize/2 *[self.label numberOfLines]; 164 | 165 | self.label.frame = CGRectMake(0, 0, CGRectGetHeight(self.loaderView.frame), self.fontSize*2+10); 166 | self.label.center = CGPointMake(xPoint, yPoint); 167 | } 168 | 169 | 170 | #pragma mark - Animate 171 | 172 | - (void)startAnimating 173 | { 174 | if (!self.animate) return; 175 | [self animateDrop]; 176 | } 177 | 178 | - (void)animateDrop { 179 | self.mainBall.alpha = 1.0; 180 | self.fallingBall.hidden = NO; 181 | self.fallingBall.center = CGPointMake(CGRectGetWidth(self.loaderView.frame)/2, 0); 182 | 183 | [self.mainAnimator addBehavior:self.gravityBehaviour]; 184 | [self.mainAnimator addBehavior:self.collisionBehaviour]; 185 | } 186 | 187 | - (void)animateMainBall { 188 | 189 | POPSpringAnimation *bounds = [POPSpringAnimation animationWithPropertyNamed:kPOPViewBounds]; 190 | if (CGRectGetWidth(self.mainBall.frame) + self.amountZoom >= self.maxDiam) { 191 | bounds.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 0, 0)]; 192 | bounds.springBounciness = 0; 193 | bounds.springSpeed = 20; 194 | } 195 | else { 196 | bounds.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, CGRectGetWidth(self.mainBall.frame) + self.amountZoom, CGRectGetWidth(self.mainBall.frame) + self.amountZoom)]; 197 | bounds.springBounciness = 20; 198 | bounds.springSpeed = 0; 199 | } 200 | bounds.delegate = self; 201 | [bounds setValue:@"bounds" forKey:@"identifier"]; 202 | [self.mainBall pop_addAnimation:bounds forKey:@"animateBounds"]; 203 | 204 | POPSpringAnimation *radius = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerCornerRadius]; 205 | if (CGRectGetWidth(self.mainBall.frame) + self.amountZoom >= self.maxDiam) { 206 | radius.toValue = @0; 207 | radius.springSpeed = 20; 208 | radius.springBounciness = 0; 209 | } 210 | else { 211 | radius.toValue = @(CGRectGetWidth(self.mainBall.frame)/2 + self.amountZoom/2); 212 | radius.springSpeed = 0; 213 | radius.springBounciness = 20; 214 | } 215 | [self.mainBall.layer pop_addAnimation:radius forKey:@"animateRadius"]; 216 | 217 | [self performSelector:@selector(animateDrop) withObject:nil afterDelay: self.delay]; 218 | } 219 | 220 | - (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id)item withBoundaryIdentifier:(id)identifier atPoint:(CGPoint)p { 221 | if (self.animate && [@"boundary" isEqualToString:(NSString *)identifier]) { 222 | self.fallingBall.hidden = YES; 223 | [self animateMainBall]; 224 | for (UIDynamicBehavior *behaviour in self.mainAnimator.behaviors) { 225 | [self.mainAnimator removeBehavior:behaviour]; 226 | } 227 | } 228 | } 229 | 230 | 231 | #pragma mark - Custom setters 232 | 233 | - (void)setBackgroundColor:(UIColor *)backgroundColor 234 | { 235 | [super setBackgroundColor:[UIColor clearColor]]; 236 | self.loaderView.backgroundColor = backgroundColor; 237 | self.loaderView.layer.backgroundColor = backgroundColor.CGColor; 238 | } 239 | 240 | - (void)setLoaderColor:(UIColor *)loaderColor 241 | { 242 | _loaderColor = loaderColor; 243 | self.mainBall.backgroundColor = loaderColor; 244 | self.fallingBall.backgroundColor = loaderColor; 245 | } 246 | 247 | - (void)setCornerRadius:(CGFloat)cornerRadius 248 | { 249 | _cornerRadius = cornerRadius; 250 | self.loaderView.layer.cornerRadius = cornerRadius; 251 | } 252 | 253 | - (void)setLoaderAlpha:(CGFloat)loaderAlpha 254 | { 255 | _loaderAlpha = loaderAlpha; 256 | self.loaderView.alpha = loaderAlpha; 257 | self.mainBall.alpha = loaderAlpha; 258 | self.fallingBall.alpha = loaderAlpha; 259 | } 260 | 261 | 262 | #pragma mark - Lazy inits 263 | 264 | - (UIView *)loaderView 265 | { 266 | if (!_loaderView) { 267 | _loaderView = [UIView new]; 268 | [_loaderView setClipsToBounds:YES]; 269 | [self addSubview:_loaderView]; 270 | } 271 | return _loaderView; 272 | } 273 | 274 | - (UIView *)fallingBall 275 | { 276 | if (!_fallingBall) { 277 | _fallingBall = [UIView new]; 278 | [self.loaderView addSubview:_fallingBall]; 279 | } 280 | return _fallingBall; 281 | } 282 | 283 | - (UIView *)mainBall 284 | { 285 | if (!_mainBall) { 286 | _mainBall = [UIView new]; 287 | [self.loaderView addSubview:_mainBall]; 288 | } 289 | return _mainBall; 290 | } 291 | 292 | - (UIDynamicAnimator *)mainAnimator 293 | { 294 | if (!_mainAnimator) _mainAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.loaderView]; 295 | return _mainAnimator; 296 | } 297 | 298 | - (UIGravityBehavior *)gravityBehaviour 299 | { 300 | _gravityBehaviour = [[UIGravityBehavior alloc] initWithItems:@[self.fallingBall]]; 301 | _gravityBehaviour.magnitude = 0.85; 302 | return _gravityBehaviour; 303 | } 304 | 305 | - (UICollisionBehavior *)collisionBehaviour 306 | { 307 | _collisionBehaviour = [[UICollisionBehavior alloc] initWithItems:@[self.fallingBall]]; 308 | _collisionBehaviour.translatesReferenceBoundsIntoBoundary = YES; 309 | _collisionBehaviour.collisionDelegate = self; 310 | [_collisionBehaviour addBoundaryWithIdentifier:@"boundary" 311 | fromPoint:CGPointMake(self.mainBall.center.x - 10, self.mainBall.center.y - self.mainBall.frame.size.height/2) 312 | toPoint:CGPointMake(self.mainBall.center.x + 10, self.mainBall.center.y - self.mainBall.frame.size.height/2)]; 313 | return _collisionBehaviour; 314 | } 315 | 316 | - (UILabel *)label 317 | { 318 | if (!_label) { 319 | _label = [UILabel new]; 320 | } 321 | return _label; 322 | } 323 | 324 | 325 | #pragma mark - Deprecated methods 326 | 327 | - (instancetype)initLoaderOnView:(UIView *)view 328 | { 329 | return [PQFBallDrop createLoaderOnView:view]; 330 | } 331 | 332 | 333 | #pragma mark - Draw rect for IB_DESIGNABLE 334 | 335 | - (void)drawRect:(CGRect)rect 336 | { 337 | #if TARGET_INTERFACE_BUILDER 338 | self.loaderView.frame = CGRectMake(0, 0, self.frame.size.width, self.maxDiam + 30); 339 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 340 | self.mainBall.bounds = CGRectMake(0, 0, self.maxDiam/2, self.maxDiam/2); 341 | self.hidden = NO; 342 | [self layoutBalls]; 343 | self.mainBall.bounds = CGRectMake(0, 0, self.maxDiam/2, self.maxDiam/2); 344 | self.mainBall.layer.cornerRadius = self.maxDiam/4; 345 | #endif 346 | } 347 | 348 | @end 349 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFBarsInCircle.h: -------------------------------------------------------------------------------- 1 | // 2 | // PQFBarsInCircle.h 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PQFLoader.h" 11 | 12 | IB_DESIGNABLE 13 | @interface PQFBarsInCircle : PQFLoader 14 | /** Text label of the Loader. Hidden if text is nil */ 15 | @property (nonatomic, strong) IBInspectable UILabel *label; 16 | /** Corner radius of the Loader background */ 17 | @property (nonatomic, assign) IBInspectable CGFloat cornerRadius; 18 | /** Color of the Loader */ 19 | @property (nonatomic, strong) IBInspectable UIColor *loaderColor; 20 | /** Alpha of the loader */ 21 | @property (nonatomic, assign) IBInspectable CGFloat loaderAlpha; 22 | /** Size of the label text */ 23 | @property (nonatomic, assign) IBInspectable CGFloat fontSize; 24 | /** Number of rotating bars */ 25 | @property (nonatomic, assign) IBInspectable CGFloat numberOfBars; 26 | /** Minimum height of the bars */ 27 | @property (nonatomic, assign) IBInspectable CGFloat barHeightMin; 28 | /** Maximum height of the bars */ 29 | @property (nonatomic, assign) IBInspectable CGFloat barHeightMax; 30 | /** Minimum width of the bars */ 31 | @property (nonatomic, assign) IBInspectable CGFloat barWidthMin; 32 | /** Maximum width of the bars */ 33 | @property (nonatomic, assign) IBInspectable CGFloat barWidthMax; 34 | /** Rotation speed in seconds (Less amount, more speed) */ 35 | @property (nonatomic, assign) IBInspectable CGFloat rotationSpeed; 36 | /** Bar size speed in seconds (Less amount, more speed) */ 37 | @property (nonatomic, assign) IBInspectable CGFloat barsSpeed; 38 | /** Alpha of the hole view */ 39 | @property (nonatomic, assign) IBInspectable CGFloat alpha; 40 | @end 41 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFBarsInCircle.m: -------------------------------------------------------------------------------- 1 | // 2 | // PQFBarsInCircle.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "PQFBarsInCircle.h" 10 | #import 11 | 12 | #define degreesToRadians(x) (M_PI * x /180.0) 13 | 14 | @interface PQFBarsInCircle () 15 | @property (nonatomic, strong) UIView *loaderView; 16 | @property (nonatomic, strong) CALayer *loaderLayer; 17 | 18 | @property (nonatomic, strong) NSArray *bars; 19 | @property (nonatomic, strong) NSMutableArray *widthsArray; 20 | @property (nonatomic, strong) NSMutableArray *heightArray; 21 | @property (nonatomic, assign) BOOL animate; 22 | @property (nonatomic) CGFloat angleInRad; 23 | @end 24 | 25 | @implementation PQFBarsInCircle 26 | 27 | 28 | #pragma mark - IB_DESIGNABLE 29 | 30 | - (id)initWithCoder:(NSCoder *)aDecoder 31 | { 32 | self = [super initWithCoder:aDecoder]; 33 | if (self) { 34 | [self initialSetupWithView:nil]; 35 | } 36 | return self; 37 | } 38 | 39 | #pragma mark - PQFLoader methods 40 | 41 | + (instancetype)showLoaderOnView:(UIView *)view 42 | { 43 | PQFBarsInCircle *loader = [self createLoaderOnView:view]; 44 | [loader showLoader]; 45 | return loader; 46 | } 47 | 48 | + (instancetype)createLoaderOnView:(UIView *)view 49 | { 50 | if (!view) view = [[UIApplication sharedApplication].delegate window]; 51 | PQFBarsInCircle *loader = [PQFBarsInCircle new]; 52 | [loader initialSetupWithView:view]; 53 | return loader; 54 | } 55 | 56 | - (void)showLoader 57 | { 58 | [self performSelector:@selector(startShowingLoader) withObject:nil afterDelay:0]; 59 | } 60 | 61 | - (void)startShowingLoader 62 | { 63 | self.hidden = NO; 64 | self.animate = YES; 65 | [self generateLoader]; 66 | [self startAnimating]; 67 | } 68 | 69 | - (void)hideLoader 70 | { 71 | self.hidden = YES; 72 | self.animate = NO; 73 | } 74 | 75 | - (void)removeLoader 76 | { 77 | [self hideLoader]; 78 | [self removeFromSuperview]; 79 | } 80 | 81 | 82 | #pragma mark - Prepare loader 83 | 84 | - (void)initialSetupWithView:(UIView *)view 85 | { 86 | //Setting up frame 87 | self.frame = view.frame; 88 | self.center = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)); 89 | 90 | //If it is modal, background for the loader 91 | if ([view isKindOfClass:[UIWindow class]]) { 92 | UIView *bgView = [[UIView alloc] initWithFrame:view.bounds]; 93 | bgView.backgroundColor = [UIColor colorWithWhite:0.2 alpha:0.6]; 94 | [self addSubview:bgView]; 95 | } 96 | 97 | //Add loader to its superview 98 | [view addSubview:self]; 99 | 100 | [self.loaderView addSubview:self.label]; 101 | 102 | //Initial Values 103 | [self defaultValues]; 104 | 105 | //Initially hidden 106 | self.hidden = YES; 107 | } 108 | 109 | - (void)defaultValues 110 | { 111 | [super setBackgroundColor:[UIColor clearColor]]; 112 | self.numberOfBars = 35; 113 | self.loaderAlpha = 1.0; 114 | self.cornerRadius = 0; 115 | self.loaderColor = [UIColor flatTurquoiseColor]; 116 | self.barHeightMin = 20; 117 | self.barHeightMax = 32; 118 | self.barWidthMin = 2; 119 | self.barWidthMax = 4; 120 | self.angleInRad = degreesToRadians(0); 121 | self.rotationSpeed = 6.0; 122 | self.barsSpeed = 0.5; 123 | self.fontSize = 14.0; 124 | } 125 | 126 | 127 | #pragma mark - Before showing 128 | 129 | 130 | - (void)generateLoader 131 | { 132 | self.loaderView.frame = CGRectMake(0, 0, self.frame.size.width, self.barHeightMax*2 + 10); 133 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 134 | self.loaderLayer.frame = self.loaderView.bounds; 135 | self.loaderLayer.cornerRadius = self.cornerRadius; 136 | 137 | [self layoutBars]; 138 | 139 | if (self.label.text) [self layoutLabel]; 140 | } 141 | 142 | - (void)layoutBars 143 | { 144 | NSMutableArray *temp = [NSMutableArray new]; 145 | for (int i = 0 ; i < self.numberOfBars ; i++) { 146 | CALayer *bar = [CALayer layer]; 147 | bar.backgroundColor = self.loaderColor.CGColor; 148 | [self.heightArray addObject:[NSNumber numberWithFloat:0]]; 149 | [self.widthsArray addObject:[NSNumber numberWithFloat:0]]; 150 | bar.bounds = CGRectMake(0, 0, 0, 0); 151 | bar.anchorPoint = CGPointMake(0.5, 1.0); 152 | bar.position = CGPointMake(CGRectGetWidth(self.loaderView.frame)/2, CGRectGetHeight(self.loaderView.frame)/2); 153 | if (self.label.text) { 154 | bar.position = CGPointMake(bar.position.x, bar.position.y + 10); 155 | } 156 | CGFloat angle = degreesToRadians(360/self.numberOfBars*(i+1)); 157 | CATransform3D rotate = CATransform3DMakeRotation(angle, 0, 0, 1); 158 | bar.transform = rotate; 159 | [temp addObject:bar]; 160 | [self.loaderLayer addSublayer:bar]; 161 | } 162 | self.bars = [temp copy]; 163 | } 164 | 165 | - (void)layoutLabel 166 | { 167 | self.label.textAlignment = NSTextAlignmentCenter; 168 | self.label.numberOfLines = 3; 169 | self.label.textColor = [UIColor whiteColor]; 170 | self.label.font = [UIFont systemFontOfSize:self.fontSize]; 171 | 172 | CGFloat xCenter = self.center.x; 173 | CGFloat yCenter = self.center.y; 174 | 175 | self.loaderView.frame = CGRectMake(self.loaderView.frame.origin.x, self.loaderView.frame.origin.y, self.loaderView.frame.size.width, self.loaderView.frame.size.height + 10 + self.fontSize*2+10 ); 176 | 177 | self.frame = CGRectMake(0, 0, self.frame.size.width, self.loaderView.frame.size.height + 10 ); 178 | self.center = CGPointMake(xCenter, yCenter); 179 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 180 | 181 | CGFloat xPoint = CGRectGetWidth(self.loaderView.frame)/2; 182 | CGFloat yPoint = CGRectGetHeight(self.loaderView.frame) - self.fontSize/2 *[self.label numberOfLines]; 183 | 184 | self.label.frame = CGRectMake(0, 0, CGRectGetHeight(self.loaderView.frame), self.fontSize*2+10); 185 | self.label.center = CGPointMake(xPoint, yPoint); 186 | } 187 | 188 | 189 | #pragma mark - Animate 190 | 191 | - (void)startAnimating 192 | { 193 | if (!self.animate) return; 194 | [self animateRotation]; 195 | [self animateBars]; 196 | } 197 | 198 | - (void)animateBars 199 | { 200 | for (int i = 0; i < self.numberOfBars; i++) { 201 | CALayer *bar = [self.bars objectAtIndex:i]; 202 | [self animateBar:bar atIndex:i]; 203 | } 204 | } 205 | 206 | - (void)animateBar:(CALayer *)bar atIndex:(NSInteger)index { 207 | 208 | NSNumber *widthInArray = [self.widthsArray objectAtIndex:index]; 209 | CGFloat width = [widthInArray floatValue]; 210 | CGFloat width2 = [self randomFloatBetween:self.barWidthMin and:self.barWidthMax]; 211 | [self.widthsArray replaceObjectAtIndex:index withObject:[NSNumber numberWithFloat:width2]]; 212 | 213 | NSNumber *heightInArray = [self.heightArray objectAtIndex:index]; 214 | CGFloat height = [heightInArray floatValue]; 215 | CGFloat height2 = [self randomFloatBetween:self.barHeightMin and:self.barHeightMax]; 216 | [self.heightArray replaceObjectAtIndex:index withObject:[NSNumber numberWithFloat:height2]]; 217 | 218 | CAKeyframeAnimation *heightMoving = [CAKeyframeAnimation animationWithKeyPath:@"bounds.size"]; 219 | heightMoving.duration = self.barsSpeed; 220 | heightMoving.values = @[[NSValue valueWithCGSize:CGSizeMake(width, height)], 221 | [NSValue valueWithCGSize:CGSizeMake(width2, height2)]]; 222 | heightMoving.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]]; 223 | heightMoving.fillMode = kCAFillModeForwards; 224 | heightMoving.removedOnCompletion = NO; 225 | 226 | if (index == self.numberOfBars -1) { 227 | heightMoving.delegate = self; 228 | [heightMoving setValue:@"anim1" forKey:@"animation"]; 229 | } 230 | 231 | [bar addAnimation:heightMoving forKey:@"height"]; 232 | } 233 | 234 | - (void)animateRotation { 235 | if (!self.animate) return; 236 | CAKeyframeAnimation *rotate = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; 237 | rotate.duration = self.rotationSpeed; 238 | rotate.additive = YES; 239 | rotate.values = @[[NSNumber numberWithFloat:self.angleInRad], [NSNumber numberWithFloat:(self.angleInRad + M_PI_4)]]; 240 | rotate.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]]; 241 | rotate.delegate = self; 242 | rotate.fillMode = kCAFillModeForwards; 243 | rotate.removedOnCompletion = NO; 244 | 245 | [rotate setValue:@"anim2" forKey:@"animation"]; 246 | 247 | self.angleInRad = self.angleInRad + M_PI_4; 248 | [self.loaderLayer addAnimation:rotate forKey:@"rotation"]; 249 | } 250 | 251 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { 252 | if (!self.animate) return; 253 | if ([@"anim1" isEqualToString:[anim valueForKey:@"animation"]]) { 254 | [self animateBars]; 255 | } 256 | if ([@"anim2" isEqualToString:[anim valueForKey:@"animation"]]) { 257 | [self animateRotation]; 258 | } 259 | } 260 | 261 | 262 | #pragma mark - Custom setters 263 | 264 | - (void)setBackgroundColor:(UIColor *)backgroundColor 265 | { 266 | [super setBackgroundColor:[UIColor clearColor]]; 267 | self.loaderView.backgroundColor = backgroundColor; 268 | self.loaderView.layer.backgroundColor = backgroundColor.CGColor; 269 | } 270 | 271 | - (void)setLoaderAlpha:(CGFloat)loaderAlpha 272 | { 273 | _loaderAlpha = loaderAlpha; 274 | self.loaderView.alpha = loaderAlpha; 275 | } 276 | 277 | - (void)setCornerRadius:(CGFloat)cornerRadius 278 | { 279 | _cornerRadius = cornerRadius; 280 | self.loaderView.layer.cornerRadius = cornerRadius; 281 | } 282 | 283 | - (void)setLoaderColor:(UIColor *)loaderColor 284 | { 285 | _loaderColor = loaderColor; 286 | [self performSelector:@selector(changeBarsColor:) withObject:loaderColor afterDelay:0]; 287 | } 288 | 289 | - (void)changeBarsColor:(UIColor *)loaderColor 290 | { 291 | CGColorRef color = loaderColor.CGColor; 292 | for (CALayer *layer in self.bars) { 293 | layer.backgroundColor = color; 294 | } 295 | } 296 | 297 | #pragma mark - Lazy inits 298 | 299 | - (UIView *)loaderView 300 | { 301 | if (!_loaderView) { 302 | _loaderView = [UIView new]; 303 | [self addSubview:_loaderView]; 304 | } 305 | return _loaderView; 306 | } 307 | 308 | - (CALayer *)loaderLayer 309 | { 310 | if (!_loaderLayer) { 311 | _loaderLayer = [CALayer layer]; 312 | [self.loaderView.layer addSublayer:_loaderLayer]; 313 | } 314 | return _loaderLayer; 315 | } 316 | 317 | - (NSMutableArray *)widthsArray 318 | { 319 | if (!_widthsArray) _widthsArray = [NSMutableArray new]; 320 | return _widthsArray; 321 | } 322 | 323 | - (NSMutableArray *)heightArray 324 | { 325 | if (!_heightArray) _heightArray = [NSMutableArray new]; 326 | return _heightArray; 327 | } 328 | 329 | - (UILabel *)label 330 | { 331 | if (!_label) { 332 | _label = [UILabel new]; 333 | } 334 | return _label; 335 | } 336 | 337 | 338 | #pragma mark - Helper 339 | 340 | - (CGFloat)randomFloatBetween:(CGFloat)a and:(CGFloat)b { 341 | CGFloat random = ((CGFloat) rand()) / (CGFloat) RAND_MAX; 342 | CGFloat diff = b - a; 343 | CGFloat r = random * diff; 344 | return a + r; 345 | } 346 | 347 | 348 | #pragma mark - Deprecated methods 349 | 350 | - (instancetype)initLoaderOnView:(UIView *)view 351 | { 352 | return [PQFBarsInCircle createLoaderOnView:view]; 353 | } 354 | 355 | 356 | #pragma mark - Draw rect for IB_DESIGNABLE 357 | 358 | - (void)drawRect:(CGRect)rect 359 | { 360 | #if TARGET_INTERFACE_BUILDER 361 | self.loaderView.frame = CGRectMake(0, 0, self.frame.size.width, self.barHeightMax*2 + 10); 362 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 363 | self.hidden = NO; 364 | 365 | NSMutableArray *temp = [NSMutableArray new]; 366 | for (int i = 0 ; i < self.numberOfBars ; i++) { 367 | CALayer *bar = [CALayer layer]; 368 | bar.backgroundColor = self.loaderColor.CGColor; 369 | bar.bounds = CGRectMake(0, 0, [self randomFloatBetween:self.barWidthMin and:self.barWidthMax], [self randomFloatBetween:self.barHeightMin and:self.barHeightMax]); 370 | bar.anchorPoint = CGPointMake(0.5, 1.0); 371 | bar.position = CGPointMake(CGRectGetWidth(self.loaderView.frame)/2, CGRectGetHeight(self.loaderView.frame)/2); 372 | if (self.label.text) { 373 | bar.position = CGPointMake(bar.position.x, bar.position.y + 10); 374 | } 375 | CGFloat angle = degreesToRadians(360/self.numberOfBars*(i+1)); 376 | CATransform3D rotate = CATransform3DMakeRotation(angle, 0, 0, 1); 377 | bar.transform = rotate; 378 | [temp addObject:bar]; 379 | [self.loaderLayer addSublayer:bar]; 380 | } 381 | self.bars = [temp copy]; 382 | #endif 383 | } 384 | 385 | @end 386 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFBouncingBalls.h: -------------------------------------------------------------------------------- 1 | // 2 | // PQFBouncingBalls.h 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PQFLoader.h" 11 | 12 | IB_DESIGNABLE 13 | @interface PQFBouncingBalls : PQFLoader 14 | /** Text label of the Loader. Hidden if text is nil */ 15 | @property (nonatomic, strong) IBInspectable UILabel *label; 16 | /** Corner radius of the Loader background */ 17 | @property (nonatomic, assign) IBInspectable CGFloat cornerRadius; 18 | /** Color of the Loader */ 19 | @property (nonatomic, strong) IBInspectable UIColor *loaderColor; 20 | /** Alpha of the loader */ 21 | @property (nonatomic, assign) IBInspectable CGFloat loaderAlpha; 22 | /** Diameter of the bouncing balls */ 23 | @property (nonatomic, assign) IBInspectable CGFloat diameter; 24 | /** Movement amount on the X axis */ 25 | @property (nonatomic, assign) IBInspectable CGFloat jumpAmount; 26 | /** Separation between the bouncing balls */ 27 | @property (nonatomic, assign) IBInspectable CGFloat separation; 28 | /** Ball added size when jumping */ 29 | @property (nonatomic, assign) IBInspectable CGFloat zoomAmount; 30 | /** Duration of each animation */ 31 | @property (nonatomic, assign) IBInspectable CGFloat duration; 32 | /** Size of the label text */ 33 | @property (nonatomic, assign) IBInspectable CGFloat fontSize; 34 | /** Alpha of the hole view */ 35 | @property (nonatomic, assign) IBInspectable CGFloat alpha; 36 | @end 37 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFBouncingBalls.m: -------------------------------------------------------------------------------- 1 | // 2 | // PQFBouncingBalls.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "PQFBouncingBalls.h" 10 | #import 11 | 12 | @interface PQFBouncingBalls () 13 | @property (nonatomic, strong) UIView *loaderView; 14 | @property (nonatomic) CALayer *ball1; 15 | @property (nonatomic) CALayer *ball2; 16 | @property (nonatomic) CALayer *ball3; 17 | @property (nonatomic, assign) BOOL animate; 18 | @property (nonatomic) CGFloat rectSize; 19 | @end 20 | 21 | @implementation PQFBouncingBalls 22 | 23 | 24 | #pragma mark - IB_DESIGNABLE 25 | 26 | - (id)initWithCoder:(NSCoder *)aDecoder 27 | { 28 | self = [super initWithCoder:aDecoder]; 29 | if (self) { 30 | [self initialSetupWithView:nil]; 31 | } 32 | return self; 33 | } 34 | 35 | #pragma mark - PQFLoader methods 36 | 37 | + (instancetype)showLoaderOnView:(UIView *)view 38 | { 39 | PQFBouncingBalls *loader = [self createLoaderOnView:view]; 40 | [loader showLoader]; 41 | return loader; 42 | } 43 | 44 | + (instancetype)createLoaderOnView:(UIView *)view 45 | { 46 | if (!view) view = [[UIApplication sharedApplication].delegate window]; 47 | PQFBouncingBalls *loader = [PQFBouncingBalls new]; 48 | [loader initialSetupWithView:view]; 49 | return loader; 50 | } 51 | 52 | - (void)showLoader 53 | { 54 | [self performSelector:@selector(startShowingLoader) withObject:nil afterDelay:0]; 55 | } 56 | 57 | - (void)startShowingLoader 58 | { 59 | self.hidden = NO; 60 | self.animate = YES; 61 | [self generateLoader]; 62 | [self startAnimating]; 63 | } 64 | 65 | - (void)hideLoader 66 | { 67 | self.hidden = YES; 68 | self.animate = NO; 69 | } 70 | 71 | - (void)removeLoader 72 | { 73 | [self hideLoader]; 74 | [self removeFromSuperview]; 75 | } 76 | 77 | 78 | #pragma mark - Prepare loader 79 | 80 | - (void)initialSetupWithView:(UIView *)view 81 | { 82 | //Setting up frame 83 | self.frame = view.frame; 84 | self.center = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)); 85 | 86 | //If it is modal, background for the loader 87 | if ([view isKindOfClass:[UIWindow class]]) { 88 | UIView *bgView = [[UIView alloc] initWithFrame:view.bounds]; 89 | bgView.backgroundColor = [UIColor colorWithWhite:0.2 alpha:0.6]; 90 | [self addSubview:bgView]; 91 | } 92 | 93 | //Add loader to its superview 94 | [view addSubview:self]; 95 | 96 | [self.loaderView addSubview:self.label]; 97 | 98 | //Initial Values 99 | [self defaultValues]; 100 | 101 | //Initially hidden 102 | self.hidden = YES; 103 | } 104 | 105 | - (void)defaultValues 106 | { 107 | [super setBackgroundColor:[UIColor clearColor]]; 108 | self.cornerRadius = 0; 109 | self.loaderAlpha = 1.0; 110 | self.loaderColor = [UIColor flatTurquoiseColor]; 111 | self.diameter = 16; 112 | self.jumpAmount = 50; 113 | self.separation = 20; 114 | self.zoomAmount = 20; 115 | self.duration = 1.0; 116 | self.fontSize = 14.0; 117 | self.rectSize = self.diameter + self.jumpAmount + self.zoomAmount/2; 118 | } 119 | 120 | 121 | #pragma mark - Before showing 122 | 123 | - (void)generateLoader 124 | { 125 | self.loaderView.frame = CGRectMake(0, 0, self.frame.size.width, self.rectSize + 30); 126 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 127 | self.loaderView.layer.cornerRadius = self.cornerRadius; 128 | 129 | [self layoutBalls]; 130 | 131 | if (self.label.text) [self layoutLabel]; 132 | } 133 | 134 | - (void)layoutBalls 135 | { 136 | self.ball1.bounds = CGRectMake(0, 0, self.diameter, self.diameter); 137 | self.ball1.cornerRadius = self.diameter/2; 138 | self.ball1.backgroundColor = self.loaderColor.CGColor; 139 | self.ball1.opacity = self.loaderAlpha; 140 | 141 | self.ball2.bounds = CGRectMake(0, 0, self.diameter, self.diameter); 142 | self.ball2.cornerRadius = self.diameter/2; 143 | self.ball2.backgroundColor = self.loaderColor.CGColor; 144 | self.ball2.opacity = self.loaderAlpha; 145 | 146 | self.ball3.bounds = CGRectMake(0, 0, self.diameter, self.diameter); 147 | self.ball3.cornerRadius = self.diameter/2; 148 | self.ball3.backgroundColor = self.loaderColor.CGColor; 149 | self.ball3.opacity = self.loaderAlpha; 150 | 151 | self.ball1.position = CGPointMake(CGRectGetWidth(self.frame)/2 - self.separation, CGRectGetHeight(self.frame)/2 + self.jumpAmount/2); 152 | self.ball2.position = CGPointMake(CGRectGetWidth(self.frame)/2 , CGRectGetHeight(self.frame)/2 + self.jumpAmount/2); 153 | self.ball3.position = CGPointMake(CGRectGetWidth(self.frame)/2 + self.separation, CGRectGetHeight(self.frame)/2 + self.jumpAmount/2); 154 | } 155 | 156 | - (void)layoutLabel 157 | { 158 | self.label.textAlignment = NSTextAlignmentCenter; 159 | self.label.numberOfLines = 3; 160 | self.label.textColor = [UIColor whiteColor]; 161 | self.label.font = [UIFont systemFontOfSize:self.fontSize]; 162 | 163 | self.ball1.position = CGPointMake(self.ball1.position.x, self.ball1.position.y - 10); 164 | self.ball2.position = CGPointMake(self.ball2.position.x, self.ball2.position.y - 10); 165 | self.ball3.position = CGPointMake(self.ball3.position.x, self.ball3.position.y - 10); 166 | 167 | self.loaderView.frame = CGRectMake(self.loaderView.frame.origin.x, self.loaderView.frame.origin.y, self.loaderView.frame.size.width, self.loaderView.frame.size.height + 10 + self.fontSize*2+10 ); 168 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 169 | 170 | CGFloat xPoint = CGRectGetWidth(self.loaderView.frame)/2; 171 | CGFloat yPoint = CGRectGetHeight(self.loaderView.frame) - self.fontSize/2 *[self.label numberOfLines]; 172 | 173 | self.label.frame = CGRectMake(0, 0, CGRectGetHeight(self.loaderView.frame), self.fontSize*2+10); 174 | self.label.center = CGPointMake(xPoint, yPoint); 175 | } 176 | 177 | 178 | #pragma mark - Animate 179 | 180 | - (void)startAnimating 181 | { 182 | if (!self.animate) return; 183 | [self animateToLeft]; 184 | [self animateToRight]; 185 | } 186 | 187 | - (void)animateToLeft 188 | { 189 | if (!self.animate) return; 190 | CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position.y"]; 191 | animation.duration = self.duration; 192 | animation.values = @[@(self.ball1.position.y), @(self.ball1.position.y - self.jumpAmount), @(self.ball1.position.y)]; 193 | animation.timingFunctions = @[[CAMediaTimingFunction functionWithControlPoints:0.5 :-1 :1.0 :1.0],[CAMediaTimingFunction functionWithControlPoints:0.8 :0.0 :0.8 :0.0]]; 194 | animation.beginTime = CACurrentMediaTime(); 195 | 196 | CAKeyframeAnimation *down = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; 197 | down.duration = self.duration; 198 | down.values = @[@(self.ball2.position.x), @(self.ball2.position.x -self.separation/2 ), @(self.ball2.position.x -self.separation)]; 199 | down.timingFunctions = @[[CAMediaTimingFunction functionWithControlPoints:0.5 :-1 :1.0 :1.0],[CAMediaTimingFunction functionWithControlPoints:0.8 :0.0 :0.8 :0.0]]; 200 | down.beginTime = CACurrentMediaTime(); 201 | 202 | CAKeyframeAnimation *move = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; 203 | move.duration = self.duration; 204 | move.values = @[@(self.ball1.position.x), @(self.ball1.position.x +self.separation/2 ), @(self.ball1.position.x +self.separation)]; 205 | move.timingFunctions = @[[CAMediaTimingFunction functionWithControlPoints:0.5 :-1 :1.0 :1.0],[CAMediaTimingFunction functionWithControlPoints:0.8 :0.0 :0.8 :0.0]]; 206 | move.beginTime = CACurrentMediaTime(); 207 | 208 | CAKeyframeAnimation *miniBounds = [CAKeyframeAnimation animationWithKeyPath:@"bounds.size"]; 209 | miniBounds.duration = self.duration; 210 | miniBounds.values = @[[NSValue valueWithCGSize:CGSizeMake(self.ball1.frame.size.width, self.ball1.frame.size.height)], 211 | [NSValue valueWithCGSize:CGSizeMake(self.ball1.frame.size.width + self.zoomAmount, self.ball1.frame.size.height +self.zoomAmount)], 212 | [NSValue valueWithCGSize:CGSizeMake(self.ball1.frame.size.width , self.ball1.frame.size.height)]]; 213 | miniBounds.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]]; 214 | 215 | CAKeyframeAnimation *radius = [CAKeyframeAnimation animationWithKeyPath:@"cornerRadius"]; 216 | radius.duration = self.duration; 217 | radius.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]]; 218 | radius.values = @[@(self.diameter/2), @((self.diameter + self.zoomAmount)/2), @(self.diameter/2)]; 219 | 220 | [self.ball2 addAnimation:miniBounds forKey:@"miniBounds"]; 221 | [self.ball2 addAnimation:down forKey:@"anything2"]; 222 | [self.ball2 addAnimation:animation forKey:@"anything"]; 223 | [self.ball1 addAnimation:move forKey:@"anything3"]; 224 | [self.ball2 addAnimation:radius forKey:@"radius"]; 225 | } 226 | 227 | - (void)animateToRight 228 | { 229 | if (!self.animate) return; 230 | CAKeyframeAnimation *animation2 = [CAKeyframeAnimation animationWithKeyPath:@"position.y"]; 231 | animation2.duration = self.duration; 232 | animation2.values = @[@(self.ball2.position.y), @(self.ball2.position.y - self.jumpAmount), @(self.ball2.position.y)]; 233 | animation2.timingFunctions = @[[CAMediaTimingFunction functionWithControlPoints:0.5 :-1 :1.0 :1.0],[CAMediaTimingFunction functionWithControlPoints:0.8 :0.0 :0.8 :0.0]]; 234 | animation2.beginTime = CACurrentMediaTime() + self.duration; 235 | 236 | CAKeyframeAnimation *down2 = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; 237 | down2.duration = self.duration; 238 | down2.values = @[@(self.ball2.position.x), @(self.ball2.position.x + self.separation/2 ), @(self.ball2.position.x +self.separation)]; 239 | down2.timingFunctions = @[[CAMediaTimingFunction functionWithControlPoints:0.5 :-1 :1.0 :1.0],[CAMediaTimingFunction functionWithControlPoints:0.8 :0.0 :0.8 :0.0]]; 240 | down2.beginTime = CACurrentMediaTime() + self.duration; 241 | 242 | CAKeyframeAnimation *move2 = [CAKeyframeAnimation animationWithKeyPath:@"position.x"]; 243 | move2.duration = self.duration; 244 | move2.delegate = self; 245 | move2.values = @[@(self.ball3.position.x), @(self.ball3.position.x - self.separation/2 ), @(self.ball3.position.x - self.separation)]; 246 | move2.timingFunctions = @[[CAMediaTimingFunction functionWithControlPoints:0.5 :-1 :1.0 :1.0],[CAMediaTimingFunction functionWithControlPoints:0.8 :0.0 :0.8 :0.0]]; 247 | move2.beginTime = CACurrentMediaTime() + self.duration ; 248 | 249 | CAKeyframeAnimation *miniBounds2 = [CAKeyframeAnimation animationWithKeyPath:@"bounds.size"]; 250 | miniBounds2.duration = self.duration; 251 | miniBounds2.values = @[[NSValue valueWithCGSize:CGSizeMake(self.ball2.frame.size.width, self.ball2.frame.size.height)], 252 | [NSValue valueWithCGSize:CGSizeMake(self.ball2.frame.size.width + self.zoomAmount, self.ball2.frame.size.height + self.zoomAmount)], 253 | [NSValue valueWithCGSize:CGSizeMake(self.ball2.frame.size.width , self.ball2.frame.size.height)]]; 254 | miniBounds2.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]]; 255 | miniBounds2.beginTime = CACurrentMediaTime() + self.duration ; 256 | 257 | CAKeyframeAnimation *radius2 = [CAKeyframeAnimation animationWithKeyPath:@"cornerRadius"]; 258 | radius2.duration = self.duration; 259 | radius2.values = @[@(self.diameter/2), @((self.diameter + self.zoomAmount)/2), @(self.diameter/2)]; 260 | radius2.beginTime = CACurrentMediaTime() + self.duration; 261 | radius2.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]]; 262 | 263 | [self.ball2 addAnimation:animation2 forKey:@"anything5"]; 264 | [self.ball2 addAnimation:down2 forKey:@"anything6"]; 265 | [self.ball3 addAnimation:move2 forKey:@"anything4"]; 266 | [self.ball2 addAnimation:miniBounds2 forKey:@"miniBounds2"]; 267 | [self.ball2 addAnimation:radius2 forKey:@"radius2"]; 268 | } 269 | 270 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { 271 | [self startAnimating]; 272 | } 273 | 274 | 275 | #pragma mark - Custom setters 276 | 277 | - (void)setBackgroundColor:(UIColor *)backgroundColor 278 | { 279 | [super setBackgroundColor:[UIColor clearColor]]; 280 | self.loaderView.backgroundColor = backgroundColor; 281 | self.loaderView.layer.backgroundColor = backgroundColor.CGColor; 282 | } 283 | 284 | - (void)setLoaderAlpha:(CGFloat)loaderAlpha 285 | { 286 | _loaderAlpha = loaderAlpha; 287 | self.loaderView.alpha = loaderAlpha; 288 | } 289 | 290 | - (void)setCornerRadius:(CGFloat)cornerRadius 291 | { 292 | _cornerRadius = cornerRadius; 293 | self.loaderView.layer.cornerRadius = cornerRadius; 294 | } 295 | 296 | - (void)setLoaderColor:(UIColor *)loaderColor 297 | { 298 | _loaderColor = loaderColor; 299 | [self performSelector:@selector(changeBallsColor:) withObject:loaderColor afterDelay:0]; 300 | } 301 | 302 | - (void)changeBallsColor:(UIColor *)loaderColor 303 | { 304 | self.ball1.backgroundColor = loaderColor.CGColor; 305 | self.ball2.backgroundColor = loaderColor.CGColor; 306 | self.ball3.backgroundColor = loaderColor.CGColor; 307 | } 308 | 309 | 310 | #pragma mark - Lazy inits 311 | 312 | - (UIView *)loaderView 313 | { 314 | if (!_loaderView) { 315 | _loaderView = [UIView new]; 316 | [self addSubview:_loaderView]; 317 | } 318 | return _loaderView; 319 | } 320 | 321 | - (CALayer *)ball1 322 | { 323 | if (!_ball1) { 324 | _ball1 = [CALayer layer]; 325 | [self.layer addSublayer:_ball1]; 326 | } 327 | return _ball1; 328 | } 329 | 330 | - (CALayer *)ball2 331 | { 332 | if (!_ball2) { 333 | _ball2 = [CALayer layer]; 334 | [self.layer addSublayer:_ball2]; 335 | } 336 | return _ball2; 337 | } 338 | 339 | - (CALayer *)ball3 340 | { 341 | if (!_ball3) { 342 | _ball3 = [CALayer layer]; 343 | [self.layer addSublayer:_ball3]; 344 | } 345 | return _ball3; 346 | } 347 | 348 | - (UILabel *)label 349 | { 350 | if (!_label) { 351 | _label = [UILabel new]; 352 | } 353 | return _label; 354 | } 355 | 356 | 357 | #pragma mark - Deprecated methods 358 | 359 | - (instancetype)initLoaderOnView:(UIView *)view 360 | { 361 | return [PQFBouncingBalls createLoaderOnView:view]; 362 | } 363 | 364 | 365 | #pragma mark - Draw rect for IB_DESIGNABLE 366 | 367 | - (void)drawRect:(CGRect)rect 368 | { 369 | #if TARGET_INTERFACE_BUILDER 370 | self.rectSize = self.diameter + self.jumpAmount + self.zoomAmount/2; 371 | self.loaderView.frame = CGRectMake(0, 0, self.superview.frame.size.width, self.rectSize + 30); 372 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 373 | self.hidden = NO; 374 | [self generateLoader]; 375 | #endif 376 | } 377 | 378 | @end 379 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFCirclesInTriangle.h: -------------------------------------------------------------------------------- 1 | // 2 | // PQFCirclesInTriangle.h 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PQFLoader.h" 11 | 12 | IB_DESIGNABLE 13 | @interface PQFCirclesInTriangle : PQFLoader 14 | /** Text label of the Loader. Hidden if text is nil */ 15 | @property (nonatomic, strong) IBInspectable UILabel *label; 16 | /** Corner radius of the Loader background */ 17 | @property (nonatomic, assign) IBInspectable CGFloat cornerRadius; 18 | /** Color of the Loader */ 19 | @property (nonatomic, strong) IBInspectable UIColor *loaderColor; 20 | /** Alpha of the loader */ 21 | @property (nonatomic, assign) IBInspectable CGFloat loaderAlpha; 22 | /** Duration of each animation */ 23 | @property (nonatomic, assign) IBInspectable CGFloat duration; 24 | /** Size of the label text */ 25 | @property (nonatomic, assign) IBInspectable CGFloat fontSize; 26 | /** Number of circles to animate. 3 or 6 are the recommended values */ 27 | @property (nonatomic, assign) IBInspectable CGFloat numberOfCircles; 28 | /** Maximum diameter of the circles */ 29 | @property (nonatomic, assign) IBInspectable CGFloat maxDiam; 30 | /** Separation between the circles */ 31 | @property (nonatomic, assign) IBInspectable CGFloat separation; 32 | /** Border width of the circles*/ 33 | @property (nonatomic, assign) IBInspectable CGFloat borderWidth; 34 | /** Delay between the animations */ 35 | @property (nonatomic, assign) IBInspectable CGFloat delay; 36 | /** Alpha of the hole view */ 37 | @property (nonatomic, assign) IBInspectable CGFloat alpha; 38 | @end 39 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFCirclesInTriangle.m: -------------------------------------------------------------------------------- 1 | // 2 | // PQFCirclesInTriangle.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "PQFCirclesInTriangle.h" 10 | #import 11 | 12 | @interface PQFCirclesInTriangle () 13 | @property (nonatomic, strong) UIView *loaderView; 14 | @property (nonatomic, strong) CALayer *loaderLayer; 15 | @property (nonatomic, strong) NSArray *circles; 16 | @property (nonatomic, assign) BOOL animate; 17 | @property (nonatomic) CGFloat rectSize; 18 | @end 19 | 20 | @implementation PQFCirclesInTriangle 21 | 22 | 23 | #pragma mark - IB_DESIGNABLE 24 | 25 | - (id)initWithCoder:(NSCoder *)aDecoder 26 | { 27 | self = [super initWithCoder:aDecoder]; 28 | if (self) { 29 | [self initialSetupWithView:nil]; 30 | } 31 | return self; 32 | } 33 | 34 | 35 | #pragma mark - PQFLoader methods 36 | 37 | + (instancetype)showLoaderOnView:(UIView *)view 38 | { 39 | PQFCirclesInTriangle *loader = [self createLoaderOnView:view]; 40 | [loader showLoader]; 41 | return loader; 42 | } 43 | 44 | + (instancetype)createLoaderOnView:(UIView *)view 45 | { 46 | if (!view) view = [[UIApplication sharedApplication].delegate window]; 47 | PQFCirclesInTriangle *loader = [PQFCirclesInTriangle new]; 48 | [loader initialSetupWithView:view]; 49 | return loader; 50 | } 51 | 52 | - (void)showLoader 53 | { 54 | [self performSelector:@selector(startShowingLoader) withObject:nil afterDelay:0]; 55 | } 56 | 57 | - (void)startShowingLoader 58 | { 59 | self.hidden = NO; 60 | self.animate = YES; 61 | [self generateLoader]; 62 | [self startAnimating]; 63 | } 64 | 65 | - (void)hideLoader 66 | { 67 | self.hidden = YES; 68 | self.animate = NO; 69 | } 70 | 71 | - (void)removeLoader 72 | { 73 | [self hideLoader]; 74 | [self removeFromSuperview]; 75 | } 76 | 77 | 78 | #pragma mark - Prepare loader 79 | 80 | - (void)initialSetupWithView:(UIView *)view 81 | { 82 | //Setting up frame 83 | self.frame = view.frame; 84 | self.center = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)); 85 | 86 | //If it is modal, background for the loader 87 | if ([view isKindOfClass:[UIWindow class]]) { 88 | UIView *bgView = [[UIView alloc] initWithFrame:view.bounds]; 89 | bgView.backgroundColor = [UIColor colorWithWhite:0.2 alpha:0.6]; 90 | [self addSubview:bgView]; 91 | } 92 | 93 | //Add loader to its superview 94 | [view addSubview:self]; 95 | 96 | [self.loaderView addSubview:self.label]; 97 | 98 | //Initial Values 99 | [self defaultValues]; 100 | 101 | //Initially hidden 102 | self.hidden = YES; 103 | } 104 | 105 | - (void)defaultValues 106 | { 107 | [super setBackgroundColor:[UIColor clearColor]]; 108 | self.numberOfCircles = 6; 109 | self.cornerRadius = 0; 110 | self.loaderAlpha = 1.0; 111 | self.loaderColor = [UIColor flatTurquoiseColor]; 112 | self.maxDiam = 50; 113 | self.separation = 8.0; 114 | self.borderWidth = 2.0; 115 | self.delay = 0.5; 116 | self.duration = 2.0; 117 | self.fontSize = 14.0; 118 | self.rectSize = self.separation*2 + self.maxDiam; 119 | } 120 | 121 | 122 | #pragma mark - Before showing 123 | 124 | 125 | - (void)generateLoader 126 | { 127 | self.loaderView.frame = CGRectMake(0, 0, self.frame.size.width, self.rectSize + 10); 128 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 129 | 130 | self.loaderLayer.frame = self.loaderView.bounds; 131 | self.loaderLayer.cornerRadius = self.cornerRadius; 132 | 133 | [self layoutCircles]; 134 | 135 | if (self.label.text) [self layoutLabel]; 136 | } 137 | 138 | - (void)layoutCircles 139 | { 140 | NSMutableArray *temp = [NSMutableArray new]; 141 | 142 | for (int i = 0; i< self.numberOfCircles; i++) { 143 | CALayer *circle = [CALayer layer]; 144 | circle.bounds = CGRectMake(0, 0, 0 , 0); 145 | circle.borderWidth = self.borderWidth; 146 | circle.borderColor = self.loaderColor.CGColor; 147 | if (i == 0 || i == 3) { 148 | circle.position = CGPointMake(CGRectGetWidth(self.loaderView.frame)/2, CGRectGetHeight(self.loaderView.frame)/2 -self.separation); 149 | } 150 | if (i == 1 || i == 4) { 151 | circle.position = CGPointMake(CGRectGetWidth(self.loaderView.frame)/2 - self.separation, CGRectGetHeight(self.loaderView.frame)/2 + self.separation); 152 | } 153 | if (i == 2 || i == 5) { 154 | circle.position = CGPointMake(CGRectGetWidth(self.loaderView.frame)/2 + self.separation, CGRectGetHeight(self.loaderView.frame)/2 + self.separation); 155 | } 156 | if (self.label.text) { circle.position = CGPointMake(circle.position.x, circle.position.y + 10); } 157 | [temp addObject:circle]; 158 | [self.loaderLayer addSublayer:circle]; 159 | } 160 | self.circles = temp; 161 | } 162 | 163 | - (void)layoutLabel 164 | { 165 | self.label.textAlignment = NSTextAlignmentCenter; 166 | self.label.numberOfLines = 3; 167 | self.label.textColor = [UIColor whiteColor]; 168 | self.label.font = [UIFont systemFontOfSize:self.fontSize]; 169 | 170 | CGFloat xCenter = self.center.x; 171 | CGFloat yCenter = self.center.y; 172 | 173 | self.loaderView.frame = CGRectMake(self.loaderView.frame.origin.x, self.loaderView.frame.origin.y, self.loaderView.frame.size.width, self.loaderView.frame.size.height + 10 + self.fontSize*2+10 ); 174 | 175 | self.frame = CGRectMake(0, 0, self.frame.size.width, self.loaderView.frame.size.height + 10 ); 176 | self.center = CGPointMake(xCenter, yCenter); 177 | self.loaderView.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); 178 | 179 | CGFloat xPoint = CGRectGetWidth(self.loaderView.frame)/2; 180 | CGFloat yPoint = CGRectGetHeight(self.loaderView.frame) - self.fontSize/2 *[self.label numberOfLines]; 181 | 182 | self.label.frame = CGRectMake(0, 0, CGRectGetHeight(self.loaderView.frame), self.fontSize*2+10); 183 | self.label.center = CGPointMake(xPoint, yPoint); 184 | } 185 | 186 | 187 | #pragma mark - Animate 188 | 189 | - (void)startAnimating 190 | { 191 | if (!self.animate) return; 192 | [self firstAnimation]; 193 | if (self.numberOfCircles <= 3) return; 194 | [self performSelector:@selector(secondAnimation) withObject:nil afterDelay:self.delay]; 195 | } 196 | 197 | - (void)firstAnimation { 198 | if (!self.animate) return; 199 | int limit = (self.numberOfCircles < 4) ? self.numberOfCircles : 3; 200 | for (int i = 0; i < limit; i++) { 201 | [self animateCircle:[self.circles objectAtIndex:i] atIndex:i]; 202 | } 203 | } 204 | 205 | - (void)secondAnimation { 206 | if (!self.animate) return; 207 | for (int i = 3; i 10 | 11 | @protocol PQFLoaderProtocol 12 | + (instancetype)showLoaderOnView:(UIView *)view; 13 | + (instancetype)createLoaderOnView:(UIView *)view; 14 | - (void)showLoader; 15 | - (void)removeLoader; 16 | @end 17 | 18 | @interface PQFLoader : UIView 19 | 20 | /** 21 | * Shows a loader modally with a background alpha. 22 | * 23 | * User interaction when the loader is showing is disabled by default 24 | * 25 | * @return Even that is not necessary to do anything more, it is important to have a reference to the loader to make the removal easier 26 | */ 27 | + (instancetype)showModalLoader; 28 | 29 | /** 30 | * Shows a loader on the view that you choose. Be careful when adding to scrolling views, it is recommendet to add it modally on that case. 31 | * 32 | * @return Even that is not necessary to do anything more, it is important to have a reference to the loader to make the removal easier 33 | */ 34 | + (instancetype)showLoaderOnView:(UIView *)view; 35 | 36 | /** 37 | * Creates a loader modally with a background alpha. 38 | * 39 | * User interaction when the loader is showing is disabled by default 40 | * 41 | * @return Even that is not necessary to do anything more, it is important to have a reference to the loader to make the removal easier 42 | */ 43 | + (instancetype)createModalLoader; 44 | 45 | /** 46 | * Creates a loader on the view that you choose. Be careful when adding to scrolling views, it is recommendet to add it modally on that case. 47 | * 48 | * @return Even that is not necessary to do anything more, it is important to have a reference to the loader to make the removal easier 49 | */ 50 | + (instancetype)createLoaderOnView:(UIView *)view; 51 | 52 | /** 53 | * If for some reason yo do not have a reference to the loader, and you know where did you add it, you can use this method in order to remove from the 54 | * subview of the UIView passed as parameter. 55 | * 56 | * Try to avoid using this method, it is more expensive than having a reference to it an call the "removeLoader" method. 57 | * 58 | * @param view View where you know that is you loader as a subview. 59 | */ 60 | + (void)removeAllLoadersOnView:(UIView *)view; 61 | 62 | - (void)showLoader; 63 | - (void)removeLoader; 64 | 65 | #pragma mark Deprecated methods 66 | 67 | - (instancetype)initLoaderOnView:(UIView *)view __deprecated_msg("Use '+createLoader:onView:'"); 68 | - (void)remove __deprecated_msg("Use 'removeLoader'"); 69 | - (void)show __deprecated_msg("User 'showLoader'"); 70 | - (void)hide __deprecated_msg("Use 'removeLoader'"); 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /PQFCustomLoaders/PQFLoader.m: -------------------------------------------------------------------------------- 1 | // 2 | // PQFLoader.m 3 | // PQFCustomLoadersDemo 4 | // 5 | // Created by Pol Quintana on 6/3/15. 6 | // Copyright (c) 2015 Pol Quintana. All rights reserved. 7 | // 8 | 9 | #import "PQFLoader.h" 10 | 11 | @implementation PQFLoader 12 | 13 | 14 | #pragma mark - SHOW methods 15 | 16 | + (instancetype)showModalLoader 17 | { 18 | return [self showModalLoader]; 19 | } 20 | 21 | + (instancetype)showLoaderOnView:(UIView *)view 22 | { 23 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 24 | reason:[NSString stringWithFormat:@"PQFLoader is an abstract class, use a loader type class"] 25 | userInfo:nil]; 26 | } 27 | 28 | - (void)showLoader {} 29 | 30 | 31 | #pragma mark - CREATE methods 32 | 33 | + (instancetype)createModalLoader 34 | { 35 | return [self createLoaderOnView:nil]; 36 | } 37 | 38 | + (instancetype)createLoaderOnView:(UIView *)view 39 | { 40 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 41 | reason:[NSString stringWithFormat:@"PQFLoader is an abstract class, use a loader type class"] 42 | userInfo:nil]; 43 | } 44 | 45 | 46 | #pragma mark - REMOVE methods 47 | 48 | + (void)removeAllLoadersOnView:(UIView *)view 49 | { 50 | for (UIView *subview in view.subviews) { 51 | if ([subview isKindOfClass:[PQFLoader class]]) { 52 | [subview removeFromSuperview]; 53 | } 54 | } 55 | } 56 | 57 | - (void)removeLoader {} 58 | 59 | 60 | #pragma mark - Deprecated methods 61 | 62 | - (instancetype)initLoaderOnView:(UIView *)view { return nil; } 63 | 64 | - (void)show 65 | { 66 | [self showLoader]; 67 | } 68 | 69 | - (void)hide 70 | { 71 | [self removeLoader]; 72 | } 73 | 74 | - (void)remove 75 | { 76 | [self removeLoader]; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://img.shields.io/badge/language-ObjectiveC-blue.svg) 2 | ![](https://img.shields.io/badge/version-1.1.0-red.svg) 3 | #PQFCustomLoaders 1.1.0 4 | 5 | ####Collection of highly customizable loaders for your iOS projects. 6 | 7 |

8 | 9 |

10 | 11 |

12 | PQFBouncingBalls 13 |

14 | 15 |

16 | 17 |

18 | 19 |

20 | PQFBarsInCircles 21 |

22 | 23 |

24 | 25 |

26 | 27 |

28 | PQFCirclesInTriangle 29 |

30 | 31 |

32 | 33 |

34 | 35 |

36 | PQFBallDrop 37 |

38 | 39 | ###Changelog 40 | * __1.1.0__ (24 May 2015) 41 | - __IB Designable properties__- Thanks __[@dfreniche](https://github.com/dfreniche)__! 42 | - New __Inspectable Demo__ with IBDesignable properties examples (See Interface Builder section) 43 | - Improvements 44 | * __1.0.1__ (9 May 2015) 45 | - __New Modal presentation__ 46 | - __New Loader__(PQFBallDrop) 47 | - New demo 48 | - New methods to create the loaders 49 | - All the properties are now with description 50 | 51 | - Fixed layout problems in some rare cases 52 | - Improvements 53 | * __0.0.1__ Initial version 54 | 55 | 56 | Demo Apps 57 | -------- 58 | 59 |

60 | PQFCustomLoaders Demo: 61 |

62 | 63 |

64 | 65 |

66 | 67 |

68 | Inspectable Demo: 69 |

70 | 71 |

72 | 73 |

74 | 75 | Installation 76 | -------- 77 | ___ 78 | 79 | ###CocoaPods 80 | 81 | The easiest way to get started is to use [CocoaPods](http://cocoapods.org/). Just add the following line to your Podfile: 82 | 83 | ``` pod 'PQFCustomLoaders', '~> 1.1.0' ``` 84 | 85 | ###Import the project 86 | If you don't want to use (you should) ``CocoaPods``, you can download this project, and add the files in the ``/PQFCustomLoaders`` folder to your existing project. 87 | 88 | Quick Start 89 | -------- 90 | ___ 91 | 92 | ####1. Import 93 | 94 | The first thing is to import the main file. This file contain all the requiered imports that you are going to need. If you are planning to use only one loader, you can import only the required one, it is up to you. 95 | 96 | ``` 97 | #import 98 | ``` 99 | 100 | ####2. Create a loader: 101 | 102 | For example, if you are going to add the ``PQFBouncingBalls`` Loader, you have to initialize it like this. 103 | I recommend you to make a property in order to have a pointer to the loader for when you want to remove it. 104 | 105 | ``` 106 | @interface MyClass () 107 | ... 108 | 109 | @property (nonatomic, strong) PQFBouncingBalls *bouncingBalls; 110 | 111 | ... 112 | @end 113 | ``` 114 | #####2. 1 In a view 115 | 116 | ``` 117 | @implementation MyClass 118 | ... 119 | 120 | self.loader = [PQFBouncingBalls createLoaderOnView:self.view]; 121 | 122 | ... 123 | @end 124 | ``` 125 | In this example I am adding the loader to the main view, but you can add it to any UIView (or subclass) 126 | 127 | #####2. 2 As a modal 128 | 129 | ``` 130 | @implementation MyClass 131 | ... 132 | 133 | self.loader = [PQFBouncingBalls createModalLoader]; 134 | 135 | ... 136 | @end 137 | ``` 138 | 139 | ####3. Customize it 140 | You can customize this loaders a lot, in the following section (``Loader Styles``) you can see all the custom properties that you can change. 141 | 142 | ``` 143 | self.loader.jumpAmount = 50; 144 | self.loader.zoomAmount = 20; 145 | self.loader.separation = 20; 146 | ``` 147 | __The only properties that can be changes once the loader is on screen are:__ 148 | 149 | * cornerRadius 150 | * loaderColor 151 | * loaderAlpha 152 | * backgroundColor 153 | 154 | But it is __highly recommended__ to change them before showing 155 | 156 | 157 | ####4. Show it! 158 | When the loader is initialized, it is going to be added to the subviews of the view that you choose. But it is going to be with alpha 0.0 and with no animations activated (so no memory problems ;) ). 159 | 160 | ``` 161 | [self.loader showLoader]; 162 | ``` 163 | When you use the ``show`` method, you are making it visible and activating the animations 164 | 165 | ####5. Remove it 166 | If you are not going to use it anymore, just remove it 167 | 168 | ``` 169 | [self.loader removeLoader] 170 | ``` 171 | This method is going to remove it from it superview. 172 | 173 | 174 | ###Methods you can use: 175 | 176 | ``` 177 | + (instancetype)showModalLoader; 178 | + (instancetype)showLoaderOnView:(UIView *)view; 179 | + (instancetype)createModalLoader; 180 | + (instancetype)createLoaderOnView:(UIView *)view; 181 | + (void)removeAllLoadersOnView:(UIView *)view; 182 | 183 | - (void)showLoader; 184 | - (void)removeLoader; 185 | 186 | DEPRECATED METHODS: 187 | 188 | - (instancetype)initLoaderOnView:(UIView *)view ("Use '+createLoader:onView:'"); 189 | - (void)remove ("Use 'removeLoader'"); 190 | - (void)show ("Use 'showLoader'"); 191 | - (void)hide ("Use 'removeLoader'"); 192 | 193 | 194 | ``` 195 | 196 | 197 | Loader Styles 198 | -------- 199 | 200 | ###PQFBouncingBalls 201 | 202 | 203 | 204 | ####__Properties:__ 205 | __Text label of the Loader (Hidden if text is nil):__ label; 206 | 207 | __Corner radius of the Loader background:__ cornerRadius; 208 | 209 | __Color of the Loader:__ loaderColor; 210 | 211 | __Alpha of the loader:__ loaderAlpha; 212 | 213 | __Diameter of the bouncing balls:__ diameter; 214 | 215 | __Movement amount on the X axis:__ jumpAmount; 216 | 217 | __Separation between the bouncing balls:__ separation; 218 | 219 | __Ball added size when jumping:__ zoomAmount; 220 | 221 | __Duration of each animation:__ duration; 222 | 223 | __Size of the label text:__ fontSize; 224 | 225 | __Alpha of the hole view:__ alpha; 226 | 227 | 228 | ###PQFBarsInCircles 229 | 230 | 231 | 232 | ####__Properties:__ 233 | __Text label of the Loader (Hidden if text is nil):__ label; 234 | 235 | __Corner radius of the Loader background:__ cornerRadius; 236 | 237 | __Color of the Loader:__ loaderColor; 238 | 239 | __Alpha of the loader:__ loaderAlpha; 240 | 241 | __Duration of each animation:__ duration; 242 | 243 | __Size of the label text:__ fontSize; 244 | 245 | __Number of rotating bars:__ numberOfBars; 246 | 247 | __Minimum height of the bars:__ barHeightMin; 248 | 249 | __Maximum height of the bars:__ barHeightMax; 250 | 251 | __Minimum width of the bars:__ barWidthMin; 252 | 253 | __Maximum width of the bars:__ barWidthMax; 254 | 255 | __Rotation speed in seconds (Less amount, more speed):__ rotationSpeed; 256 | 257 | __Bar size speed in seconds (Less amount, more speed):__ barsSpeed; 258 | 259 | __Alpha of the hole view:__ alpha; 260 | 261 | ###PQFCirclesInTriangle 262 | 263 | 264 | 265 | ####__Properties:__ 266 | __Text label of the Loader (Hidden if text is nil):__ label; 267 | 268 | __Corner radius of the Loader background:__ cornerRadius; 269 | 270 | __Color of the Loader:__ loaderColor; 271 | 272 | __Alpha of the loader:__ loaderAlpha; 273 | 274 | __Duration of each animation:__ duration; 275 | 276 | __Size of the label text:__ fontSize; 277 | 278 | __Number of circles to animate. 3 or 6 are the recommended values:__ numberOfCircles; 279 | 280 | __Maximum diameter of the circles:__ maxDiam; 281 | 282 | __Separation between the circles:__ separation; 283 | 284 | __Border width of the circles:__ borderWidth; 285 | 286 | __Delay between the animations:__ delay; 287 | 288 | __Alpha of the hole view:__ alpha; 289 | 290 | ###PQFBallDrop 291 | 292 | 293 | 294 | ####__Properties:__ 295 | __Text label of the Loader (Hidden if text is nil):__ label; 296 | 297 | __Corner radius of the Loader background:__ cornerRadius; 298 | 299 | __Color of the Loader:__ loaderColor; 300 | 301 | __Alpha of the loader:__ loaderAlpha; 302 | 303 | __Duration of each animation:__ duration; 304 | 305 | __Size of the label text:__ fontSize; 306 | 307 | __Maximum diameter of the circles:__ maxDiam; 308 | 309 | __Delay between the animations:__ delay; 310 | 311 | __Ball added size when droping:__ amountZoom; 312 | 313 | __Alpha of the hole view:__ alpha; 314 | 315 | Interface builder 316 | ------- 317 | 318 | PQFCustomLoaders is `Interface Builder` friendly, you can easily customize any loader within the `Storyboard` 319 | 320 | 321 | 322 | 323 | 324 | 325 | Licenses 326 | -------- 327 | 328 | All source code is licensed under the MIT License. 329 | 330 | If you use it, i'll be happy to know about it. 331 | 332 | 333 | ###Pol Quintana - [@poolqf](https://twitter.com/poolqf) 334 | --------------------------------------------------------------------------------