├── AbstractView.podspec ├── AbstractView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── AbstractView.xcscheme ├── AbstractView ├── AbstractShape.swift ├── AbstractShapeView.swift ├── AbstractView.h ├── AbstractView.swift ├── Info.plist └── Shapes │ ├── DiamondShape.swift │ ├── ImageShape.swift │ ├── OvalShape.swift │ ├── RectangleShape.swift │ └── TriangleShape.swift ├── AbstractViewExample ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── space-wallpaper-29.imageset │ │ ├── Contents.json │ │ └── space-wallpaper-29.jpg │ └── sparkle.imageset │ │ ├── Contents.json │ │ └── sparkle.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist └── ViewController.swift ├── AbstractViewTests ├── AbstractViewTests.swift └── Info.plist ├── LICENSE ├── README.md └── Screenshots ├── AbstractView.gif ├── Screenshot1.png ├── Screenshot2.png └── Screenshot3.png /AbstractView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'AbstractView' 3 | s.version = '0.0.2' 4 | s.license = 'MIT' 5 | s.summary = 'The AbstractView is a simple view that can be used as a simple background view using abstract shapes and a visual effect' 6 | s.homepage = 'https://github.com/nuudles/AbstractView' 7 | s.authors = { 'Christopher Luu' => 'nuudles@gmail.com' } 8 | s.source = { :git => 'https://github.com/nuudles/AbstractView.git', :tag => s.version } 9 | 10 | s.ios.deployment_target = '8.0' 11 | s.tvos.deployment_target = '9.0' 12 | 13 | s.source_files = 'AbstractView/*.swift', 'AbstractView/Shapes/*.swift' 14 | 15 | s.requires_arc = true 16 | end 17 | -------------------------------------------------------------------------------- /AbstractView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 302E15301BFBE8BC0086DB59 /* AbstractView.h in Headers */ = {isa = PBXBuildFile; fileRef = 302E152F1BFBE8BC0086DB59 /* AbstractView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 302E15371BFBE8BC0086DB59 /* AbstractView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 302E152C1BFBE8BC0086DB59 /* AbstractView.framework */; }; 12 | 302E153C1BFBE8BC0086DB59 /* AbstractViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302E153B1BFBE8BC0086DB59 /* AbstractViewTests.swift */; }; 13 | 302E154D1BFBE9CA0086DB59 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302E154C1BFBE9CA0086DB59 /* AppDelegate.swift */; }; 14 | 302E154F1BFBE9CA0086DB59 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302E154E1BFBE9CA0086DB59 /* ViewController.swift */; }; 15 | 302E15521BFBE9CA0086DB59 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 302E15501BFBE9CA0086DB59 /* Main.storyboard */; }; 16 | 302E15541BFBE9CA0086DB59 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 302E15531BFBE9CA0086DB59 /* Assets.xcassets */; }; 17 | 302E15571BFBE9CA0086DB59 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 302E15551BFBE9CA0086DB59 /* LaunchScreen.storyboard */; }; 18 | 302E155D1BFBE9FE0086DB59 /* AbstractView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302E155C1BFBE9FE0086DB59 /* AbstractView.swift */; }; 19 | 302E155E1BFC0FCC0086DB59 /* AbstractView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 302E152C1BFBE8BC0086DB59 /* AbstractView.framework */; }; 20 | 302E15601BFC13E80086DB59 /* AbstractShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302E155F1BFC13E80086DB59 /* AbstractShape.swift */; }; 21 | 302E15631BFC15A60086DB59 /* OvalShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302E15621BFC15A60086DB59 /* OvalShape.swift */; }; 22 | 302E15651BFC37A20086DB59 /* RectangleShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302E15641BFC37A20086DB59 /* RectangleShape.swift */; }; 23 | 306B81691BFCCFAF003815AB /* TriangleShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306B81681BFCCFAF003815AB /* TriangleShape.swift */; }; 24 | 306B816B1BFCD893003815AB /* AbstractShapeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306B816A1BFCD893003815AB /* AbstractShapeView.swift */; }; 25 | 306B816F1BFD2940003815AB /* DiamondShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306B816E1BFD2940003815AB /* DiamondShape.swift */; }; 26 | 306B81711BFD33EC003815AB /* ImageShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306B81701BFD33EC003815AB /* ImageShape.swift */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 302E15381BFBE8BC0086DB59 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 302E15231BFBE8BC0086DB59 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 302E152B1BFBE8BC0086DB59; 35 | remoteInfo = AbstractView; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 302E152C1BFBE8BC0086DB59 /* AbstractView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AbstractView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 302E152F1BFBE8BC0086DB59 /* AbstractView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AbstractView.h; sourceTree = ""; }; 42 | 302E15311BFBE8BC0086DB59 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43 | 302E15361BFBE8BC0086DB59 /* AbstractViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AbstractViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 302E153B1BFBE8BC0086DB59 /* AbstractViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbstractViewTests.swift; sourceTree = ""; }; 45 | 302E153D1BFBE8BC0086DB59 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | 302E154A1BFBE9CA0086DB59 /* AbstractViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AbstractViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 302E154C1BFBE9CA0086DB59 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 48 | 302E154E1BFBE9CA0086DB59 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 49 | 302E15511BFBE9CA0086DB59 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 50 | 302E15531BFBE9CA0086DB59 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 51 | 302E15561BFBE9CA0086DB59 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 52 | 302E15581BFBE9CA0086DB59 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | 302E155C1BFBE9FE0086DB59 /* AbstractView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractView.swift; sourceTree = ""; }; 54 | 302E155F1BFC13E80086DB59 /* AbstractShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractShape.swift; sourceTree = ""; }; 55 | 302E15621BFC15A60086DB59 /* OvalShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OvalShape.swift; sourceTree = ""; }; 56 | 302E15641BFC37A20086DB59 /* RectangleShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RectangleShape.swift; sourceTree = ""; }; 57 | 306B81681BFCCFAF003815AB /* TriangleShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TriangleShape.swift; sourceTree = ""; }; 58 | 306B816A1BFCD893003815AB /* AbstractShapeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbstractShapeView.swift; sourceTree = ""; }; 59 | 306B816E1BFD2940003815AB /* DiamondShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiamondShape.swift; sourceTree = ""; }; 60 | 306B81701BFD33EC003815AB /* ImageShape.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageShape.swift; sourceTree = ""; }; 61 | /* End PBXFileReference section */ 62 | 63 | /* Begin PBXFrameworksBuildPhase section */ 64 | 302E15281BFBE8BC0086DB59 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | 302E15331BFBE8BC0086DB59 /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | 302E15371BFBE8BC0086DB59 /* AbstractView.framework in Frameworks */, 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | 302E15471BFBE9CA0086DB59 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | 302E155E1BFC0FCC0086DB59 /* AbstractView.framework in Frameworks */, 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | 302E15221BFBE8BC0086DB59 = { 91 | isa = PBXGroup; 92 | children = ( 93 | 302E152E1BFBE8BC0086DB59 /* AbstractView */, 94 | 302E153A1BFBE8BC0086DB59 /* AbstractViewTests */, 95 | 302E154B1BFBE9CA0086DB59 /* AbstractViewExample */, 96 | 302E152D1BFBE8BC0086DB59 /* Products */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | 302E152D1BFBE8BC0086DB59 /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 302E152C1BFBE8BC0086DB59 /* AbstractView.framework */, 104 | 302E15361BFBE8BC0086DB59 /* AbstractViewTests.xctest */, 105 | 302E154A1BFBE9CA0086DB59 /* AbstractViewExample.app */, 106 | ); 107 | name = Products; 108 | sourceTree = ""; 109 | }; 110 | 302E152E1BFBE8BC0086DB59 /* AbstractView */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 302E152F1BFBE8BC0086DB59 /* AbstractView.h */, 114 | 302E15311BFBE8BC0086DB59 /* Info.plist */, 115 | 302E155C1BFBE9FE0086DB59 /* AbstractView.swift */, 116 | 306B816A1BFCD893003815AB /* AbstractShapeView.swift */, 117 | 302E155F1BFC13E80086DB59 /* AbstractShape.swift */, 118 | 302E15611BFC157C0086DB59 /* Shapes */, 119 | ); 120 | path = AbstractView; 121 | sourceTree = ""; 122 | }; 123 | 302E153A1BFBE8BC0086DB59 /* AbstractViewTests */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 302E153B1BFBE8BC0086DB59 /* AbstractViewTests.swift */, 127 | 302E153D1BFBE8BC0086DB59 /* Info.plist */, 128 | ); 129 | path = AbstractViewTests; 130 | sourceTree = ""; 131 | }; 132 | 302E154B1BFBE9CA0086DB59 /* AbstractViewExample */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 302E154C1BFBE9CA0086DB59 /* AppDelegate.swift */, 136 | 302E154E1BFBE9CA0086DB59 /* ViewController.swift */, 137 | 302E15501BFBE9CA0086DB59 /* Main.storyboard */, 138 | 302E15531BFBE9CA0086DB59 /* Assets.xcassets */, 139 | 302E15551BFBE9CA0086DB59 /* LaunchScreen.storyboard */, 140 | 302E15581BFBE9CA0086DB59 /* Info.plist */, 141 | ); 142 | path = AbstractViewExample; 143 | sourceTree = ""; 144 | }; 145 | 302E15611BFC157C0086DB59 /* Shapes */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 302E15621BFC15A60086DB59 /* OvalShape.swift */, 149 | 302E15641BFC37A20086DB59 /* RectangleShape.swift */, 150 | 306B81681BFCCFAF003815AB /* TriangleShape.swift */, 151 | 306B816E1BFD2940003815AB /* DiamondShape.swift */, 152 | 306B81701BFD33EC003815AB /* ImageShape.swift */, 153 | ); 154 | path = Shapes; 155 | sourceTree = ""; 156 | }; 157 | /* End PBXGroup section */ 158 | 159 | /* Begin PBXHeadersBuildPhase section */ 160 | 302E15291BFBE8BC0086DB59 /* Headers */ = { 161 | isa = PBXHeadersBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | 302E15301BFBE8BC0086DB59 /* AbstractView.h in Headers */, 165 | ); 166 | runOnlyForDeploymentPostprocessing = 0; 167 | }; 168 | /* End PBXHeadersBuildPhase section */ 169 | 170 | /* Begin PBXNativeTarget section */ 171 | 302E152B1BFBE8BC0086DB59 /* AbstractView */ = { 172 | isa = PBXNativeTarget; 173 | buildConfigurationList = 302E15401BFBE8BC0086DB59 /* Build configuration list for PBXNativeTarget "AbstractView" */; 174 | buildPhases = ( 175 | 302E15271BFBE8BC0086DB59 /* Sources */, 176 | 302E15281BFBE8BC0086DB59 /* Frameworks */, 177 | 302E15291BFBE8BC0086DB59 /* Headers */, 178 | 302E152A1BFBE8BC0086DB59 /* Resources */, 179 | ); 180 | buildRules = ( 181 | ); 182 | dependencies = ( 183 | ); 184 | name = AbstractView; 185 | productName = AbstractView; 186 | productReference = 302E152C1BFBE8BC0086DB59 /* AbstractView.framework */; 187 | productType = "com.apple.product-type.framework"; 188 | }; 189 | 302E15351BFBE8BC0086DB59 /* AbstractViewTests */ = { 190 | isa = PBXNativeTarget; 191 | buildConfigurationList = 302E15431BFBE8BC0086DB59 /* Build configuration list for PBXNativeTarget "AbstractViewTests" */; 192 | buildPhases = ( 193 | 302E15321BFBE8BC0086DB59 /* Sources */, 194 | 302E15331BFBE8BC0086DB59 /* Frameworks */, 195 | 302E15341BFBE8BC0086DB59 /* Resources */, 196 | ); 197 | buildRules = ( 198 | ); 199 | dependencies = ( 200 | 302E15391BFBE8BC0086DB59 /* PBXTargetDependency */, 201 | ); 202 | name = AbstractViewTests; 203 | productName = AbstractViewTests; 204 | productReference = 302E15361BFBE8BC0086DB59 /* AbstractViewTests.xctest */; 205 | productType = "com.apple.product-type.bundle.unit-test"; 206 | }; 207 | 302E15491BFBE9CA0086DB59 /* AbstractViewExample */ = { 208 | isa = PBXNativeTarget; 209 | buildConfigurationList = 302E155B1BFBE9CA0086DB59 /* Build configuration list for PBXNativeTarget "AbstractViewExample" */; 210 | buildPhases = ( 211 | 302E15461BFBE9CA0086DB59 /* Sources */, 212 | 302E15471BFBE9CA0086DB59 /* Frameworks */, 213 | 302E15481BFBE9CA0086DB59 /* Resources */, 214 | ); 215 | buildRules = ( 216 | ); 217 | dependencies = ( 218 | ); 219 | name = AbstractViewExample; 220 | productName = AbstractViewExample; 221 | productReference = 302E154A1BFBE9CA0086DB59 /* AbstractViewExample.app */; 222 | productType = "com.apple.product-type.application"; 223 | }; 224 | /* End PBXNativeTarget section */ 225 | 226 | /* Begin PBXProject section */ 227 | 302E15231BFBE8BC0086DB59 /* Project object */ = { 228 | isa = PBXProject; 229 | attributes = { 230 | LastSwiftUpdateCheck = 0710; 231 | LastUpgradeCheck = 0710; 232 | ORGANIZATIONNAME = Nuudles; 233 | TargetAttributes = { 234 | 302E152B1BFBE8BC0086DB59 = { 235 | CreatedOnToolsVersion = 7.1.1; 236 | }; 237 | 302E15351BFBE8BC0086DB59 = { 238 | CreatedOnToolsVersion = 7.1.1; 239 | }; 240 | 302E15491BFBE9CA0086DB59 = { 241 | CreatedOnToolsVersion = 7.1.1; 242 | }; 243 | }; 244 | }; 245 | buildConfigurationList = 302E15261BFBE8BC0086DB59 /* Build configuration list for PBXProject "AbstractView" */; 246 | compatibilityVersion = "Xcode 3.2"; 247 | developmentRegion = English; 248 | hasScannedForEncodings = 0; 249 | knownRegions = ( 250 | en, 251 | Base, 252 | ); 253 | mainGroup = 302E15221BFBE8BC0086DB59; 254 | productRefGroup = 302E152D1BFBE8BC0086DB59 /* Products */; 255 | projectDirPath = ""; 256 | projectRoot = ""; 257 | targets = ( 258 | 302E152B1BFBE8BC0086DB59 /* AbstractView */, 259 | 302E15351BFBE8BC0086DB59 /* AbstractViewTests */, 260 | 302E15491BFBE9CA0086DB59 /* AbstractViewExample */, 261 | ); 262 | }; 263 | /* End PBXProject section */ 264 | 265 | /* Begin PBXResourcesBuildPhase section */ 266 | 302E152A1BFBE8BC0086DB59 /* Resources */ = { 267 | isa = PBXResourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | 302E15341BFBE8BC0086DB59 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | 302E15481BFBE9CA0086DB59 /* Resources */ = { 281 | isa = PBXResourcesBuildPhase; 282 | buildActionMask = 2147483647; 283 | files = ( 284 | 302E15571BFBE9CA0086DB59 /* LaunchScreen.storyboard in Resources */, 285 | 302E15541BFBE9CA0086DB59 /* Assets.xcassets in Resources */, 286 | 302E15521BFBE9CA0086DB59 /* Main.storyboard in Resources */, 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | /* End PBXResourcesBuildPhase section */ 291 | 292 | /* Begin PBXSourcesBuildPhase section */ 293 | 302E15271BFBE8BC0086DB59 /* Sources */ = { 294 | isa = PBXSourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | 302E155D1BFBE9FE0086DB59 /* AbstractView.swift in Sources */, 298 | 302E15651BFC37A20086DB59 /* RectangleShape.swift in Sources */, 299 | 306B816F1BFD2940003815AB /* DiamondShape.swift in Sources */, 300 | 306B816B1BFCD893003815AB /* AbstractShapeView.swift in Sources */, 301 | 302E15601BFC13E80086DB59 /* AbstractShape.swift in Sources */, 302 | 302E15631BFC15A60086DB59 /* OvalShape.swift in Sources */, 303 | 306B81691BFCCFAF003815AB /* TriangleShape.swift in Sources */, 304 | 306B81711BFD33EC003815AB /* ImageShape.swift in Sources */, 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | 302E15321BFBE8BC0086DB59 /* Sources */ = { 309 | isa = PBXSourcesBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | 302E153C1BFBE8BC0086DB59 /* AbstractViewTests.swift in Sources */, 313 | ); 314 | runOnlyForDeploymentPostprocessing = 0; 315 | }; 316 | 302E15461BFBE9CA0086DB59 /* Sources */ = { 317 | isa = PBXSourcesBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | 302E154F1BFBE9CA0086DB59 /* ViewController.swift in Sources */, 321 | 302E154D1BFBE9CA0086DB59 /* AppDelegate.swift in Sources */, 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | }; 325 | /* End PBXSourcesBuildPhase section */ 326 | 327 | /* Begin PBXTargetDependency section */ 328 | 302E15391BFBE8BC0086DB59 /* PBXTargetDependency */ = { 329 | isa = PBXTargetDependency; 330 | target = 302E152B1BFBE8BC0086DB59 /* AbstractView */; 331 | targetProxy = 302E15381BFBE8BC0086DB59 /* PBXContainerItemProxy */; 332 | }; 333 | /* End PBXTargetDependency section */ 334 | 335 | /* Begin PBXVariantGroup section */ 336 | 302E15501BFBE9CA0086DB59 /* Main.storyboard */ = { 337 | isa = PBXVariantGroup; 338 | children = ( 339 | 302E15511BFBE9CA0086DB59 /* Base */, 340 | ); 341 | name = Main.storyboard; 342 | sourceTree = ""; 343 | }; 344 | 302E15551BFBE9CA0086DB59 /* LaunchScreen.storyboard */ = { 345 | isa = PBXVariantGroup; 346 | children = ( 347 | 302E15561BFBE9CA0086DB59 /* Base */, 348 | ); 349 | name = LaunchScreen.storyboard; 350 | sourceTree = ""; 351 | }; 352 | /* End PBXVariantGroup section */ 353 | 354 | /* Begin XCBuildConfiguration section */ 355 | 302E153E1BFBE8BC0086DB59 /* Debug */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | ALWAYS_SEARCH_USER_PATHS = NO; 359 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 360 | CLANG_CXX_LIBRARY = "libc++"; 361 | CLANG_ENABLE_MODULES = YES; 362 | CLANG_ENABLE_OBJC_ARC = YES; 363 | CLANG_WARN_BOOL_CONVERSION = YES; 364 | CLANG_WARN_CONSTANT_CONVERSION = YES; 365 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 366 | CLANG_WARN_EMPTY_BODY = YES; 367 | CLANG_WARN_ENUM_CONVERSION = YES; 368 | CLANG_WARN_INT_CONVERSION = YES; 369 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 370 | CLANG_WARN_UNREACHABLE_CODE = YES; 371 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 372 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 373 | COPY_PHASE_STRIP = NO; 374 | CURRENT_PROJECT_VERSION = 1; 375 | DEBUG_INFORMATION_FORMAT = dwarf; 376 | ENABLE_STRICT_OBJC_MSGSEND = YES; 377 | ENABLE_TESTABILITY = YES; 378 | GCC_C_LANGUAGE_STANDARD = gnu99; 379 | GCC_DYNAMIC_NO_PIC = NO; 380 | GCC_NO_COMMON_BLOCKS = YES; 381 | GCC_OPTIMIZATION_LEVEL = 0; 382 | GCC_PREPROCESSOR_DEFINITIONS = ( 383 | "DEBUG=1", 384 | "$(inherited)", 385 | ); 386 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 387 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 388 | GCC_WARN_UNDECLARED_SELECTOR = YES; 389 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 390 | GCC_WARN_UNUSED_FUNCTION = YES; 391 | GCC_WARN_UNUSED_VARIABLE = YES; 392 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 393 | MTL_ENABLE_DEBUG_INFO = YES; 394 | ONLY_ACTIVE_ARCH = YES; 395 | SDKROOT = iphoneos; 396 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 397 | TARGETED_DEVICE_FAMILY = "1,2"; 398 | VERSIONING_SYSTEM = "apple-generic"; 399 | VERSION_INFO_PREFIX = ""; 400 | }; 401 | name = Debug; 402 | }; 403 | 302E153F1BFBE8BC0086DB59 /* Release */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ALWAYS_SEARCH_USER_PATHS = NO; 407 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 408 | CLANG_CXX_LIBRARY = "libc++"; 409 | CLANG_ENABLE_MODULES = YES; 410 | CLANG_ENABLE_OBJC_ARC = YES; 411 | CLANG_WARN_BOOL_CONVERSION = YES; 412 | CLANG_WARN_CONSTANT_CONVERSION = YES; 413 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 414 | CLANG_WARN_EMPTY_BODY = YES; 415 | CLANG_WARN_ENUM_CONVERSION = YES; 416 | CLANG_WARN_INT_CONVERSION = YES; 417 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 418 | CLANG_WARN_UNREACHABLE_CODE = YES; 419 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 420 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 421 | COPY_PHASE_STRIP = NO; 422 | CURRENT_PROJECT_VERSION = 1; 423 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 424 | ENABLE_NS_ASSERTIONS = NO; 425 | ENABLE_STRICT_OBJC_MSGSEND = YES; 426 | GCC_C_LANGUAGE_STANDARD = gnu99; 427 | GCC_NO_COMMON_BLOCKS = YES; 428 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 429 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 430 | GCC_WARN_UNDECLARED_SELECTOR = YES; 431 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 432 | GCC_WARN_UNUSED_FUNCTION = YES; 433 | GCC_WARN_UNUSED_VARIABLE = YES; 434 | IPHONEOS_DEPLOYMENT_TARGET = 9.1; 435 | MTL_ENABLE_DEBUG_INFO = NO; 436 | SDKROOT = iphoneos; 437 | TARGETED_DEVICE_FAMILY = "1,2"; 438 | VALIDATE_PRODUCT = YES; 439 | VERSIONING_SYSTEM = "apple-generic"; 440 | VERSION_INFO_PREFIX = ""; 441 | }; 442 | name = Release; 443 | }; 444 | 302E15411BFBE8BC0086DB59 /* Debug */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | CLANG_ENABLE_MODULES = YES; 448 | DEFINES_MODULE = YES; 449 | DYLIB_COMPATIBILITY_VERSION = 1; 450 | DYLIB_CURRENT_VERSION = 1; 451 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 452 | INFOPLIST_FILE = AbstractView/Info.plist; 453 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 454 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 455 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 456 | PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.AbstractView; 457 | PRODUCT_NAME = "$(TARGET_NAME)"; 458 | SKIP_INSTALL = YES; 459 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 460 | }; 461 | name = Debug; 462 | }; 463 | 302E15421BFBE8BC0086DB59 /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | CLANG_ENABLE_MODULES = YES; 467 | DEFINES_MODULE = YES; 468 | DYLIB_COMPATIBILITY_VERSION = 1; 469 | DYLIB_CURRENT_VERSION = 1; 470 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 471 | INFOPLIST_FILE = AbstractView/Info.plist; 472 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 473 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 474 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 475 | PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.AbstractView; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | SKIP_INSTALL = YES; 478 | }; 479 | name = Release; 480 | }; 481 | 302E15441BFBE8BC0086DB59 /* Debug */ = { 482 | isa = XCBuildConfiguration; 483 | buildSettings = { 484 | INFOPLIST_FILE = AbstractViewTests/Info.plist; 485 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 486 | PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.AbstractViewTests; 487 | PRODUCT_NAME = "$(TARGET_NAME)"; 488 | }; 489 | name = Debug; 490 | }; 491 | 302E15451BFBE8BC0086DB59 /* Release */ = { 492 | isa = XCBuildConfiguration; 493 | buildSettings = { 494 | INFOPLIST_FILE = AbstractViewTests/Info.plist; 495 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 496 | PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.AbstractViewTests; 497 | PRODUCT_NAME = "$(TARGET_NAME)"; 498 | }; 499 | name = Release; 500 | }; 501 | 302E15591BFBE9CA0086DB59 /* Debug */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 505 | INFOPLIST_FILE = AbstractViewExample/Info.plist; 506 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 507 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 508 | PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.AbstractViewExample; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | }; 511 | name = Debug; 512 | }; 513 | 302E155A1BFBE9CA0086DB59 /* Release */ = { 514 | isa = XCBuildConfiguration; 515 | buildSettings = { 516 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 517 | INFOPLIST_FILE = AbstractViewExample/Info.plist; 518 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 519 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 520 | PRODUCT_BUNDLE_IDENTIFIER = com.nuudles.AbstractViewExample; 521 | PRODUCT_NAME = "$(TARGET_NAME)"; 522 | }; 523 | name = Release; 524 | }; 525 | /* End XCBuildConfiguration section */ 526 | 527 | /* Begin XCConfigurationList section */ 528 | 302E15261BFBE8BC0086DB59 /* Build configuration list for PBXProject "AbstractView" */ = { 529 | isa = XCConfigurationList; 530 | buildConfigurations = ( 531 | 302E153E1BFBE8BC0086DB59 /* Debug */, 532 | 302E153F1BFBE8BC0086DB59 /* Release */, 533 | ); 534 | defaultConfigurationIsVisible = 0; 535 | defaultConfigurationName = Release; 536 | }; 537 | 302E15401BFBE8BC0086DB59 /* Build configuration list for PBXNativeTarget "AbstractView" */ = { 538 | isa = XCConfigurationList; 539 | buildConfigurations = ( 540 | 302E15411BFBE8BC0086DB59 /* Debug */, 541 | 302E15421BFBE8BC0086DB59 /* Release */, 542 | ); 543 | defaultConfigurationIsVisible = 0; 544 | defaultConfigurationName = Release; 545 | }; 546 | 302E15431BFBE8BC0086DB59 /* Build configuration list for PBXNativeTarget "AbstractViewTests" */ = { 547 | isa = XCConfigurationList; 548 | buildConfigurations = ( 549 | 302E15441BFBE8BC0086DB59 /* Debug */, 550 | 302E15451BFBE8BC0086DB59 /* Release */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | defaultConfigurationName = Release; 554 | }; 555 | 302E155B1BFBE9CA0086DB59 /* Build configuration list for PBXNativeTarget "AbstractViewExample" */ = { 556 | isa = XCConfigurationList; 557 | buildConfigurations = ( 558 | 302E15591BFBE9CA0086DB59 /* Debug */, 559 | 302E155A1BFBE9CA0086DB59 /* Release */, 560 | ); 561 | defaultConfigurationIsVisible = 0; 562 | defaultConfigurationName = Release; 563 | }; 564 | /* End XCConfigurationList section */ 565 | }; 566 | rootObject = 302E15231BFBE8BC0086DB59 /* Project object */; 567 | } 568 | -------------------------------------------------------------------------------- /AbstractView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AbstractView.xcodeproj/xcshareddata/xcschemes/AbstractView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /AbstractView/AbstractShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractShape.swift 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/17/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol AbstractShape 12 | { 13 | var relativeFrame: CGRect { get set } 14 | func drawInContext(context: CGContextRef, forRect rect: CGRect) 15 | } 16 | -------------------------------------------------------------------------------- /AbstractView/AbstractShapeView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractShapeView.swift 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/18/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class AbstractShapeView: UIView 12 | { 13 | // MARK: - Private properties 14 | private var needsShapeCreation = true 15 | private var shapeArray: [AbstractShape] = [] 16 | 17 | // MARK: - Public properties 18 | public var shapeInitializers: [ShapeInitializer] = [OvalShape.circleShapeInitializer, OvalShape.ovalShapeInitializer, RectangleShape.rectangleShapeInitializer, RectangleShape.squareShapeInitializer, TriangleShape.triangleShapeInitializer] 19 | { 20 | didSet 21 | { 22 | setNeedsShapeCreation() 23 | } 24 | } 25 | public var shapeCount = 100 26 | { 27 | didSet 28 | { 29 | setNeedsShapeCreation() 30 | } 31 | } 32 | public var minShapeSize: CGFloat? 33 | { 34 | didSet 35 | { 36 | setNeedsShapeCreation() 37 | } 38 | } 39 | public var maxShapeSize: CGFloat? 40 | { 41 | didSet 42 | { 43 | setNeedsShapeCreation() 44 | } 45 | } 46 | public var colorPalette: [UIColor]? 47 | { 48 | didSet 49 | { 50 | setNeedsShapeCreation() 51 | } 52 | } 53 | 54 | // MARK: - Initialization methods 55 | public override init(frame: CGRect) 56 | { 57 | super.init(frame: frame) 58 | initializeView() 59 | } 60 | 61 | public required init?(coder aDecoder: NSCoder) 62 | { 63 | super.init(coder: aDecoder) 64 | initializeView() 65 | } 66 | 67 | // MARK: - Private methods 68 | private func initializeView() 69 | { 70 | backgroundColor = .clearColor() 71 | contentMode = .Redraw 72 | setNeedsShapeCreation() 73 | } 74 | 75 | private func createShapes() 76 | { 77 | shapeArray = [] 78 | guard shapeInitializers.count > 0 else { return } 79 | 80 | for _ in 0 ..< shapeCount 81 | { 82 | let randomIndex = Int(arc4random_uniform(UInt32(shapeInitializers.count))) 83 | let shapeInitializer = shapeInitializers[randomIndex] 84 | 85 | let shape = shapeInitializer(relativeFrame: randomRelativeFrame(), color: randomColor()) 86 | shapeArray.append(shape) 87 | } 88 | 89 | needsShapeCreation = false 90 | } 91 | 92 | private func randomRelativeFrame() -> CGRect 93 | { 94 | return CGRect(x: CGFloat(arc4random_uniform(1000)) / 1000.0, y: CGFloat(arc4random_uniform(1000)) / 1000.0, width: CGFloat(arc4random_uniform(1000)) / 1000.0, height: CGFloat(arc4random_uniform(1000)) / 1000.0) 95 | } 96 | 97 | private func randomColor() -> UIColor 98 | { 99 | if let colorPalette = colorPalette 100 | { 101 | return colorPalette[Int(arc4random_uniform(UInt32(colorPalette.count)))] 102 | } 103 | return UIColor(red: CGFloat(arc4random_uniform(1000)) / 1000.0, green: CGFloat(arc4random_uniform(1000)) / 1000.0, blue: CGFloat(arc4random_uniform(1000)) / 1000.0, alpha: 1.0) 104 | } 105 | 106 | // MARK: - Public methods 107 | public func setNeedsShapeCreation() 108 | { 109 | needsShapeCreation = true 110 | setNeedsDisplay() 111 | } 112 | 113 | // MARK: - Drawing methodss 114 | public override func drawRect(rect: CGRect) 115 | { 116 | super.drawRect(rect) 117 | 118 | if needsShapeCreation 119 | { 120 | createShapes() 121 | } 122 | 123 | guard let context = UIGraphicsGetCurrentContext() else { return } 124 | for shape in shapeArray 125 | { 126 | let minDimension = min(bounds.size.width, bounds.size.height) 127 | let width = min(max(shape.relativeFrame.size.width * minDimension, minShapeSize ?? 0.0), maxShapeSize ?? CGFloat(FLT_MAX)) 128 | let height = min(max(shape.relativeFrame.size.height * minDimension, minShapeSize ?? 0.0), maxShapeSize ?? CGFloat(FLT_MAX)) 129 | let shapeRect = CGRect(x: shape.relativeFrame.minX * bounds.size.width - width / 2.0, y: shape.relativeFrame.minY * bounds.size.height - height / 2.0, width: width, height: height) 130 | shape.drawInContext(context, forRect: shapeRect) 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /AbstractView/AbstractView.h: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractView.h 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/17/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for AbstractView. 12 | FOUNDATION_EXPORT double AbstractViewVersionNumber; 13 | 14 | //! Project version string for AbstractView. 15 | FOUNDATION_EXPORT const unsigned char AbstractViewVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /AbstractView/AbstractView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractView.swift 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/17/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public typealias ShapeInitializer = (relativeFrame: CGRect, color: UIColor) -> (AbstractShape) 12 | 13 | public class AbstractView: UIView 14 | { 15 | // MARK: - Private UI properties 16 | private lazy var abstractShapeView: AbstractShapeView = 17 | { 18 | let abstractShapeView = AbstractShapeView() 19 | return abstractShapeView 20 | }() 21 | private lazy var visualEffectView: UIVisualEffectView = 22 | { 23 | let visualEffectView = UIVisualEffectView(effect: UIBlurEffect()) 24 | visualEffectView.translatesAutoresizingMaskIntoConstraints = false 25 | return visualEffectView 26 | }() 27 | 28 | // MARK: - Public properties 29 | public var visualEffect: UIVisualEffect? 30 | { 31 | get 32 | { 33 | return visualEffectView.effect 34 | } 35 | set 36 | { 37 | let newVisualEffectView = UIVisualEffectView(effect: newValue) 38 | visualEffectView.contentView.subviews.forEach({ newVisualEffectView.contentView.addSubview($0) }) 39 | visualEffectView.removeFromSuperview() 40 | visualEffectView = newVisualEffectView 41 | visualEffectView.translatesAutoresizingMaskIntoConstraints = false 42 | addSubview(visualEffectView) 43 | 44 | setNeedsLayout() 45 | } 46 | } 47 | public var contentView: UIView 48 | { 49 | get 50 | { 51 | return visualEffectView.contentView 52 | } 53 | } 54 | public var backgroundView: UIView? 55 | { 56 | didSet 57 | { 58 | oldValue?.removeFromSuperview() 59 | if let view = backgroundView 60 | { 61 | insertSubview(view, belowSubview: abstractShapeView) 62 | setNeedsLayout() 63 | } 64 | } 65 | } 66 | public var shapeInitializers: [ShapeInitializer] 67 | { 68 | get { return abstractShapeView.shapeInitializers } 69 | set { abstractShapeView.shapeInitializers = newValue } 70 | } 71 | public var shapeCount: Int 72 | { 73 | get { return abstractShapeView.shapeCount } 74 | set { abstractShapeView.shapeCount = newValue } 75 | } 76 | public var minShapeSize: CGFloat? 77 | { 78 | get { return abstractShapeView.minShapeSize } 79 | set { abstractShapeView.minShapeSize = newValue } 80 | } 81 | public var maxShapeSize: CGFloat? 82 | { 83 | get { return abstractShapeView.maxShapeSize } 84 | set { abstractShapeView.maxShapeSize = newValue } 85 | } 86 | public var colorPalette: [UIColor]? 87 | { 88 | get { return abstractShapeView.colorPalette } 89 | set { abstractShapeView.colorPalette = newValue } 90 | } 91 | 92 | // MARK: - Initialization methods 93 | public override init(frame: CGRect) 94 | { 95 | super.init(frame: frame) 96 | 97 | initializeView() 98 | } 99 | 100 | public required init?(coder aDecoder: NSCoder) 101 | { 102 | super.init(coder: aDecoder) 103 | 104 | initializeView() 105 | } 106 | 107 | // MARK: - Private methods 108 | private func initializeView() 109 | { 110 | addSubview(abstractShapeView) 111 | addSubview(visualEffectView) 112 | setNeedsLayout() 113 | } 114 | 115 | // MARK: - Layout methods 116 | public override func layoutSubviews() 117 | { 118 | super.layoutSubviews() 119 | 120 | backgroundView?.frame = bounds 121 | abstractShapeView.frame = bounds 122 | visualEffectView.frame = bounds 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /AbstractView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AbstractView/Shapes/DiamondShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DiamondShape.swift 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/18/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct DiamondShape: AbstractShape 12 | { 13 | // MARK: - Public constants 14 | public static let diamondShapeInitializer: ShapeInitializer = 15 | { 16 | (relativeFrame: CGRect, color: UIColor) in 17 | return DiamondShape(relativeFrame: relativeFrame, color: color) 18 | } 19 | 20 | // MARK: - Public properties 21 | public var relativeFrame: CGRect 22 | public var color: UIColor 23 | 24 | // MARK: - Initialization methods 25 | public init(relativeFrame: CGRect, color: UIColor) 26 | { 27 | self.relativeFrame = relativeFrame 28 | self.color = color 29 | } 30 | 31 | // MARK: - AbstractShape methods 32 | public func drawInContext(context: CGContextRef, forRect rect: CGRect) 33 | { 34 | CGContextSetFillColorWithColor(context, color.CGColor) 35 | CGContextBeginPath(context) 36 | CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + rect.size.height / 2.0) 37 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width / 2.0, rect.origin.y) 38 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height / 2.0) 39 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width / 2.0, rect.origin.y + rect.size.height) 40 | CGContextClosePath(context) 41 | 42 | CGContextDrawPath(context, CGPathDrawingMode.Fill) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AbstractView/Shapes/ImageShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageShape.swift 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/18/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct ImageShape: AbstractShape 12 | { 13 | // MARK: - Public properties 14 | public var relativeFrame: CGRect 15 | public var image: UIImage 16 | 17 | // MARK: - Initialization methods 18 | public init(relativeFrame: CGRect, image: UIImage) 19 | { 20 | self.relativeFrame = relativeFrame 21 | self.image = image 22 | } 23 | 24 | // MARK: - AbstractShape methods 25 | public func drawInContext(context: CGContextRef, forRect rect: CGRect) 26 | { 27 | image.drawInRect(rect) 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /AbstractView/Shapes/OvalShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OvalShape.swift 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/17/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct OvalShape: AbstractShape 12 | { 13 | // MARK: - Public constants 14 | public static let ovalShapeInitializer: ShapeInitializer = 15 | { 16 | (relativeFrame: CGRect, color: UIColor) in 17 | return OvalShape(relativeFrame: relativeFrame, color: color) 18 | } 19 | public static let circleShapeInitializer: ShapeInitializer = 20 | { 21 | (relativeFrame: CGRect, color: UIColor) in 22 | let radius = min(relativeFrame.size.width, relativeFrame.size.height) 23 | return OvalShape(relativeFrame: CGRect(x: relativeFrame.origin.x, y: relativeFrame.origin.y, width: radius, height: radius), color: color) 24 | } 25 | 26 | // MARK: - Public properties 27 | public var relativeFrame: CGRect 28 | public var color: UIColor 29 | 30 | // MARK: - Initialization methods 31 | public init(relativeFrame: CGRect, color: UIColor) 32 | { 33 | self.relativeFrame = relativeFrame 34 | self.color = color 35 | } 36 | 37 | // MARK: - AbstractShape methods 38 | public func drawInContext(context: CGContextRef, forRect rect: CGRect) 39 | { 40 | CGContextSetStrokeColorWithColor(context, color.CGColor) 41 | CGContextSetFillColorWithColor(context, color.CGColor) 42 | CGContextFillEllipseInRect(context, rect) 43 | CGContextStrokeEllipseInRect(context, rect) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AbstractView/Shapes/RectangleShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RectangleShape.swift 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/17/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct RectangleShape: AbstractShape 12 | { 13 | // MARK: - Public constants 14 | public static let rectangleShapeInitializer: ShapeInitializer = 15 | { 16 | (relativeFrame: CGRect, color: UIColor) in 17 | return RectangleShape(relativeFrame: relativeFrame, color: color) 18 | } 19 | public static let squareShapeInitializer: ShapeInitializer = 20 | { 21 | (relativeFrame: CGRect, color: UIColor) in 22 | let radius = min(relativeFrame.size.width, relativeFrame.size.height) 23 | return RectangleShape(relativeFrame: CGRect(x: relativeFrame.origin.x, y: relativeFrame.origin.y, width: radius, height: radius), color: color) 24 | } 25 | 26 | // MARK: - Public properties 27 | public var relativeFrame: CGRect 28 | public var color: UIColor 29 | 30 | // MARK: - Initialization methods 31 | public init(relativeFrame: CGRect, color: UIColor) 32 | { 33 | self.relativeFrame = relativeFrame 34 | self.color = color 35 | } 36 | 37 | // MARK: - AbstractShape methods 38 | public func drawInContext(context: CGContextRef, forRect rect: CGRect) 39 | { 40 | CGContextSetStrokeColorWithColor(context, color.CGColor) 41 | CGContextSetFillColorWithColor(context, color.CGColor) 42 | CGContextFillRect(context, rect) 43 | CGContextStrokeRect(context, rect) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /AbstractView/Shapes/TriangleShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TriangleShape.swift 3 | // AbstractView 4 | // 5 | // Created by Christopher Luu on 11/18/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct TriangleShape: AbstractShape 12 | { 13 | // MARK: - Public enums 14 | public enum Orientation 15 | { 16 | case Normal 17 | case UpsideDown 18 | case PointingLeft 19 | case PointingRight 20 | 21 | static let allValues: [Orientation] = [.Normal, .UpsideDown, .PointingLeft, .PointingRight] 22 | static let count = allValues.count 23 | } 24 | 25 | // MARK: - Public constants 26 | public static let triangleShapeInitializer: ShapeInitializer = 27 | { 28 | (relativeFrame: CGRect, color: UIColor) in 29 | return TriangleShape(relativeFrame: relativeFrame, color: color) 30 | } 31 | 32 | // MARK: - Public properties 33 | public var relativeFrame: CGRect 34 | public var color: UIColor 35 | public var orientation: Orientation 36 | 37 | // MARK: - Initialization methods 38 | public init(relativeFrame: CGRect, color: UIColor, orientation: Orientation) 39 | { 40 | self.relativeFrame = relativeFrame 41 | self.color = color 42 | self.orientation = orientation 43 | 44 | } 45 | 46 | init(relativeFrame: CGRect, color: UIColor) 47 | { 48 | self.init(relativeFrame: relativeFrame, color: color, orientation: Orientation.allValues[Int(arc4random_uniform(UInt32(Orientation.count)))]) 49 | } 50 | 51 | // MARK: - AbstractShape methods 52 | public func drawInContext(context: CGContextRef, forRect rect: CGRect) 53 | { 54 | CGContextSetFillColorWithColor(context, color.CGColor) 55 | CGContextBeginPath(context) 56 | switch orientation 57 | { 58 | case .Normal: 59 | CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + rect.size.height) 60 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width / 2.0, rect.origin.y) 61 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height) 62 | case .UpsideDown: 63 | CGContextMoveToPoint(context, rect.origin.x, rect.origin.y) 64 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width / 2.0, rect.origin.y + rect.size.height) 65 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y) 66 | case .PointingLeft: 67 | CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + rect.size.height / 2.0) 68 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y) 69 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height) 70 | case .PointingRight: 71 | CGContextMoveToPoint(context, rect.origin.x, rect.origin.y) 72 | CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + rect.size.height / 2.0) 73 | CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height) 74 | } 75 | CGContextClosePath(context) 76 | 77 | CGContextDrawPath(context, CGPathDrawingMode.Fill) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /AbstractViewExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AbstractViewExample 4 | // 5 | // Created by Christopher Luu on 11/17/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /AbstractViewExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /AbstractViewExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /AbstractViewExample/Assets.xcassets/space-wallpaper-29.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "space-wallpaper-29.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AbstractViewExample/Assets.xcassets/space-wallpaper-29.imageset/space-wallpaper-29.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuudles/AbstractView/fa16cf41a68714347315717151f2341659a49f55/AbstractViewExample/Assets.xcassets/space-wallpaper-29.imageset/space-wallpaper-29.jpg -------------------------------------------------------------------------------- /AbstractViewExample/Assets.xcassets/sparkle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "sparkle.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AbstractViewExample/Assets.xcassets/sparkle.imageset/sparkle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuudles/AbstractView/fa16cf41a68714347315717151f2341659a49f55/AbstractViewExample/Assets.xcassets/sparkle.imageset/sparkle.png -------------------------------------------------------------------------------- /AbstractViewExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /AbstractViewExample/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 | -------------------------------------------------------------------------------- /AbstractViewExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /AbstractViewExample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // AbstractViewExample 4 | // 5 | // Created by Christopher Luu on 11/17/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AbstractView 11 | 12 | class ViewController: UIViewController 13 | { 14 | // MARK: - Private properties 15 | @IBOutlet private weak var abstractView: AbstractView! 16 | 17 | // MARK: - Private UI properties 18 | private lazy var backgroundButton: UIButton = 19 | { 20 | let button = UIButton(type: UIButtonType.System) 21 | button.setTitle("Turn on background image", forState: .Normal) 22 | button.addTarget(self, action: #selector(ViewController.toggleButtonTapped(_:)), forControlEvents: .TouchUpInside) 23 | return button 24 | }() 25 | private lazy var visualEffectButton: UIButton = 26 | { 27 | let button = UIButton(type: UIButtonType.System) 28 | button.setTitle("Light blur", forState: .Normal) 29 | button.addTarget(self, action: #selector(ViewController.toggleButtonTapped(_:)), forControlEvents: .TouchUpInside) 30 | return button 31 | }() 32 | private lazy var shapeButton: UIButton = 33 | { 34 | let button = UIButton(type: UIButtonType.System) 35 | button.setTitle("Only circles", forState: .Normal) 36 | button.addTarget(self, action: #selector(ViewController.toggleButtonTapped(_:)), forControlEvents: .TouchUpInside) 37 | return button 38 | }() 39 | private lazy var paletteButton: UIButton = 40 | { 41 | let button = UIButton(type: UIButtonType.System) 42 | button.setTitle("Blue palette", forState: .Normal) 43 | button.addTarget(self, action: #selector(ViewController.toggleButtonTapped(_:)), forControlEvents: .TouchUpInside) 44 | return button 45 | }() 46 | private lazy var shapeCountLabel: UILabel = 47 | { 48 | let label = UILabel() 49 | label.textAlignment = .Center 50 | label.text = "Shape Count: \(self.abstractView.shapeCount)" 51 | label.font = UIFont.systemFontOfSize(14) 52 | return label 53 | }() 54 | private lazy var shapeCountSlider: UISlider = 55 | { 56 | let slider = UISlider() 57 | slider.minimumValue = 0 58 | slider.maximumValue = 200 59 | slider.value = Float(self.abstractView.shapeCount) 60 | slider.addTarget(self, action: #selector(ViewController.sliderValueChanged(_:)), forControlEvents: .ValueChanged) 61 | return slider 62 | }() 63 | private lazy var minShapeSizeLabel: UILabel = 64 | { 65 | let label = UILabel() 66 | label.textAlignment = .Center 67 | label.text = "Min Shape Size: None" 68 | label.font = UIFont.systemFontOfSize(14) 69 | return label 70 | }() 71 | private lazy var minShapeSizeSlider: UISlider = 72 | { 73 | let slider = UISlider() 74 | slider.minimumValue = -1 75 | slider.maximumValue = 300 76 | slider.value = -1 77 | slider.addTarget(self, action: #selector(ViewController.sliderValueChanged(_:)), forControlEvents: .ValueChanged) 78 | return slider 79 | }() 80 | private lazy var maxShapeSizeLabel: UILabel = 81 | { 82 | let label = UILabel() 83 | label.textAlignment = .Center 84 | label.text = "Max Shape Size: None" 85 | label.font = UIFont.systemFontOfSize(14) 86 | return label 87 | }() 88 | private lazy var maxShapeSizeSlider: UISlider = 89 | { 90 | let slider = UISlider() 91 | slider.minimumValue = -1 92 | slider.maximumValue = 300 93 | slider.value = -1 94 | slider.addTarget(self, action: #selector(ViewController.sliderValueChanged(_:)), forControlEvents: .ValueChanged) 95 | return slider 96 | }() 97 | 98 | private lazy var backgroundImageView: UIImageView = 99 | { 100 | let imageView = UIImageView(image: UIImage(named: "space-wallpaper-29")) 101 | imageView.contentMode = .ScaleAspectFill 102 | return imageView 103 | }() 104 | 105 | // MARK: - View methods 106 | override func viewDidLoad() 107 | { 108 | super.viewDidLoad() 109 | 110 | abstractView.contentView.addSubview(backgroundButton) 111 | abstractView.contentView.addSubview(visualEffectButton) 112 | abstractView.contentView.addSubview(shapeButton) 113 | abstractView.contentView.addSubview(paletteButton) 114 | abstractView.contentView.addSubview(shapeCountLabel) 115 | abstractView.contentView.addSubview(shapeCountSlider) 116 | abstractView.contentView.addSubview(minShapeSizeLabel) 117 | abstractView.contentView.addSubview(minShapeSizeSlider) 118 | abstractView.contentView.addSubview(maxShapeSizeLabel) 119 | abstractView.contentView.addSubview(maxShapeSizeSlider) 120 | 121 | abstractView.shapeInitializers = [OvalShape.circleShapeInitializer, OvalShape.ovalShapeInitializer, RectangleShape.squareShapeInitializer, RectangleShape.rectangleShapeInitializer, TriangleShape.triangleShapeInitializer, DiamondShape.diamondShapeInitializer, { (relativeFrame, _) in return ImageShape(relativeFrame: relativeFrame, image: UIImage(named: "sparkle")!) }] 122 | } 123 | 124 | override func viewDidLayoutSubviews() 125 | { 126 | super.viewDidLayoutSubviews() 127 | 128 | backgroundButton.frame = CGRect(x: 10, y: topLayoutGuide.length + 10, width: view.bounds.size.width - 20, height: 40) 129 | visualEffectButton.frame = CGRect(x: 10, y: backgroundButton.frame.maxY + 10, width: view.bounds.size.width - 20, height: 40) 130 | shapeButton.frame = CGRect(x: 10, y: visualEffectButton.frame.maxY + 10, width: view.bounds.size.width - 20, height: 40) 131 | paletteButton.frame = CGRect(x: 10, y: shapeButton.frame.maxY + 10, width: view.bounds.size.width - 20, height: 40) 132 | shapeCountLabel.frame = CGRect(x: 10, y: paletteButton.frame.maxY + 10, width: view.bounds.size.width - 20, height: 15) 133 | shapeCountSlider.frame = CGRect(x: 10, y: shapeCountLabel.frame.maxY + 5, width: view.bounds.size.width - 20, height: shapeCountSlider.bounds.size.height) 134 | minShapeSizeLabel.frame = CGRect(x: 10, y: shapeCountSlider.frame.maxY + 10, width: view.bounds.size.width - 20, height: 15) 135 | minShapeSizeSlider.frame = CGRect(x: 10, y: minShapeSizeLabel.frame.maxY + 5, width: view.bounds.size.width - 20, height: minShapeSizeSlider.bounds.size.height) 136 | maxShapeSizeLabel.frame = CGRect(x: 10, y: minShapeSizeSlider.frame.maxY + 10, width: view.bounds.size.width - 20, height: 15) 137 | maxShapeSizeSlider.frame = CGRect(x: 10, y: maxShapeSizeLabel.frame.maxY + 5, width: view.bounds.size.width - 20, height: maxShapeSizeSlider.bounds.size.height) 138 | } 139 | 140 | // MARK: - Button action methods 141 | func toggleButtonTapped(sender: UIButton) 142 | { 143 | sender.tag += 1 144 | switch (sender, sender.tag) 145 | { 146 | case (backgroundButton, 1): 147 | abstractView.backgroundView = backgroundImageView 148 | sender.setTitle("Turn off background image", forState: .Normal) 149 | case (backgroundButton, 2): 150 | abstractView.backgroundView = nil 151 | sender.setTitle("Turn on background image", forState: .Normal) 152 | sender.tag = 0 153 | 154 | case (visualEffectButton, 1): 155 | abstractView.visualEffect = UIBlurEffect(style: .Light) 156 | sender.setTitle("Dark blur", forState: .Normal) 157 | case (visualEffectButton, 2): 158 | abstractView.visualEffect = UIBlurEffect(style: .Dark) 159 | sender.setTitle("No visual effect", forState: .Normal) 160 | case (visualEffectButton, 3): 161 | abstractView.visualEffect = nil 162 | sender.setTitle("Extra light blur", forState: .Normal) 163 | case (visualEffectButton, 4): 164 | abstractView.visualEffect = UIBlurEffect(style: .ExtraLight) 165 | sender.setTitle("Light blur", forState: .Normal) 166 | sender.tag = 0 167 | 168 | case (shapeButton, 1): 169 | abstractView.shapeInitializers = [OvalShape.circleShapeInitializer] 170 | sender.setTitle("Circles and ovals", forState: .Normal) 171 | case (shapeButton, 2): 172 | abstractView.shapeInitializers = [OvalShape.circleShapeInitializer, OvalShape.ovalShapeInitializer] 173 | sender.setTitle("Only squares", forState: .Normal) 174 | case (shapeButton, 3): 175 | abstractView.shapeInitializers = [RectangleShape.squareShapeInitializer] 176 | sender.setTitle("Squares and rectangles", forState: .Normal) 177 | case (shapeButton, 4): 178 | abstractView.shapeInitializers = [RectangleShape.squareShapeInitializer, RectangleShape.rectangleShapeInitializer] 179 | sender.setTitle("Only triangles", forState: .Normal) 180 | case (shapeButton, 5): 181 | abstractView.shapeInitializers = [TriangleShape.triangleShapeInitializer] 182 | sender.setTitle("Only diamonds", forState: .Normal) 183 | case (shapeButton, 6): 184 | abstractView.shapeInitializers = [DiamondShape.diamondShapeInitializer] 185 | sender.setTitle("Only sparkle images", forState: .Normal) 186 | case (shapeButton, 7): 187 | abstractView.shapeInitializers = [{ (relativeFrame, _) in return ImageShape(relativeFrame: relativeFrame, image: UIImage(named: "sparkle")!) }] 188 | sender.setTitle("All shapes", forState: .Normal) 189 | case (shapeButton, 8): 190 | abstractView.shapeInitializers = [OvalShape.circleShapeInitializer, OvalShape.ovalShapeInitializer, RectangleShape.squareShapeInitializer, RectangleShape.rectangleShapeInitializer, TriangleShape.triangleShapeInitializer, DiamondShape.diamondShapeInitializer, { (relativeFrame, _) in return ImageShape(relativeFrame: relativeFrame, image: UIImage(named: "sparkle")!) }] 191 | sender.setTitle("Only circles", forState: .Normal) 192 | sender.tag = 0 193 | 194 | case (paletteButton, 1): 195 | abstractView.colorPalette = [UIColor(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0), UIColor(red: 0.0, green: 0.0, blue: 0.8, alpha: 1.0), UIColor(red: 0.0, green: 0.1, blue: 0.6, alpha: 1.0), UIColor(red: 0.0, green: 0.0, blue: 0.3, alpha: 1.0), UIColor(red: 0.0, green: 0.2, blue: 0.5, alpha: 1.0), UIColor(red: 0.0, green: 0.1, blue: 0.1, alpha: 1.0)] 196 | sender.setTitle("Red palette", forState: .Normal) 197 | case (paletteButton, 2): 198 | abstractView.colorPalette = [UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0), UIColor(red: 0.7, green: 0.0, blue: 0.0, alpha: 1.0), UIColor(red: 0.5, green: 0.0, blue: 0.0, alpha: 1.0), UIColor(red: 0.3, green: 0.0, blue: 0.0, alpha: 1.0), UIColor(red: 0.2, green: 0.0, blue: 0.0, alpha: 1.0)] 199 | sender.setTitle("Green palette", forState: .Normal) 200 | case (paletteButton, 3): 201 | abstractView.colorPalette = [UIColor(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0), UIColor(red: 0.0, green: 0.7, blue: 0.0, alpha: 1.0), UIColor(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0), UIColor(red: 0.0, green: 0.3, blue: 0.0, alpha: 1.0), UIColor(red: 0.0, green: 0.2, blue: 0.0, alpha: 1.0)] 202 | sender.setTitle("No palette", forState: .Normal) 203 | case (paletteButton, 4): 204 | abstractView.colorPalette = nil 205 | sender.setTitle("Blue palette", forState: .Normal) 206 | sender.tag = 0 207 | 208 | default: 209 | break 210 | } 211 | } 212 | 213 | // MARK: - UIControl action methods 214 | func sliderValueChanged(sender: UISlider) 215 | { 216 | switch sender 217 | { 218 | case shapeCountSlider: 219 | abstractView.shapeCount = Int(sender.value) 220 | shapeCountLabel.text = "Shape Count: \(abstractView.shapeCount)" 221 | case minShapeSizeSlider: 222 | if sender.value > 0 223 | { 224 | abstractView.minShapeSize = CGFloat(sender.value) 225 | minShapeSizeLabel.text = "Min Shape Size: \(Int(sender.value))" 226 | } 227 | else 228 | { 229 | abstractView.minShapeSize = nil 230 | minShapeSizeLabel.text = "Min Shape Size: None" 231 | } 232 | case maxShapeSizeSlider: 233 | if sender.value > 0 234 | { 235 | abstractView.maxShapeSize = CGFloat(sender.value) 236 | maxShapeSizeLabel.text = "Max Shape Size: \(Int(sender.value))" 237 | } 238 | else 239 | { 240 | abstractView.maxShapeSize = nil 241 | maxShapeSizeLabel.text = "Max Shape Size: None" 242 | } 243 | default: 244 | break 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /AbstractViewTests/AbstractViewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AbstractViewTests.swift 3 | // AbstractViewTests 4 | // 5 | // Created by Christopher Luu on 11/17/15. 6 | // Copyright © 2015 Nuudles. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AbstractView 11 | 12 | class AbstractViewTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /AbstractViewTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Christopher Luu 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AbstractView 2 | 3 | ![Screen Capture](Screenshots/AbstractView.gif) 4 | 5 | (The quality issues are GIF-related, not related to this library) 6 | 7 | ![](Screenshots/Screenshot1.png) ![](Screenshots/Screenshot2.png) ![](Screenshots/Screenshot3.png) 8 | 9 | 10 | 11 | 12 | 13 | `AbstractView ` is a simple `UIView` subclass that you can use as a background view to give some flavor compared to having just a plain white background. The way it works is by adding a bunch of abstract shapes (ovals, rectangles, etc.) and putting a `UIVisualEffectView` over the top of it. It's highly customizable, and can be extended in many ways, including the addition of other abstract shapes. 14 | 15 | ## Features 16 | 17 | - Randomly generates abstract shapes and puts a visual effect view on top of it 18 | - The visual effect can be customized 19 | - Supports adding a custom background view to the abstract view 20 | - The number of shapes can be customized 21 | - The color palette of the generated shapes can be customized 22 | - The size of the shapes can be customized 23 | - Additional abstract shapes can be supported using `ShapeInitializer` closures 24 | - The view is scalable and can be resized to fit orientation changes 25 | 26 | ## Requirements 27 | 28 | - iOS 8.0+ 29 | - tvOS 9.0+ 30 | - Xcode 7+ 31 | 32 | ## Installation using CocoaPods 33 | 34 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. 35 | 36 | Because `AbstractView ` is written in Swift, you must use frameworks. 37 | 38 | To integrate `AbstractView ` into your Xcode project using CocoaPods, specify it in your `Podfile`: 39 | 40 | ```ruby 41 | source 'https://github.com/CocoaPods/Specs.git' 42 | platform :ios, '8.0' 43 | use_frameworks! 44 | 45 | pod 'AbstractView' 46 | ``` 47 | 48 | Then, run the following command: 49 | 50 | ```bash 51 | $ pod install 52 | ``` 53 | 54 | ## Installation using Carthage 55 | 56 | Add this to your `Cartfile`: 57 | 58 | ``` 59 | github "nuudles/AbstractView" 60 | ``` 61 | 62 | ## Usage 63 | 64 | Simply add an `AbstractView` into your view hierarchy. Note that any subviews should be added to the `AbstractView`'s `contentView` 65 | 66 | ```swift 67 | let abstractView = AbstractView() 68 | self.addSubview(abstractView) 69 | 70 | abstractView.contentView.addSubview(mySubview) 71 | ``` 72 | 73 | Customize the number of abstract shapes by using the `shapeCount` property: 74 | 75 | ```swift 76 | abstractView.shapeCount = 20 77 | ``` 78 | 79 | You can customize the size of the abstract shapes using the `minShapeSize` and `maxShapeSize` properties: 80 | 81 | ```swift 82 | abstractView.minShapeSize = 50 83 | abstractView.maxShapeSize = 100 84 | ``` 85 | 86 | Change the set of colors that can be assigned to the abstract shapes by using the `colorPalette` property: 87 | 88 | ```swift 89 | abstractView.colorPalette = [UIColor(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0), UIColor(red: 0.0, green: 0.0, blue: 0.8, alpha: 1.0)] 90 | ``` 91 | 92 | Take a look at the Example project for more examples of how the abstract view can be customized. -------------------------------------------------------------------------------- /Screenshots/AbstractView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuudles/AbstractView/fa16cf41a68714347315717151f2341659a49f55/Screenshots/AbstractView.gif -------------------------------------------------------------------------------- /Screenshots/Screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuudles/AbstractView/fa16cf41a68714347315717151f2341659a49f55/Screenshots/Screenshot1.png -------------------------------------------------------------------------------- /Screenshots/Screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuudles/AbstractView/fa16cf41a68714347315717151f2341659a49f55/Screenshots/Screenshot2.png -------------------------------------------------------------------------------- /Screenshots/Screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuudles/AbstractView/fa16cf41a68714347315717151f2341659a49f55/Screenshots/Screenshot3.png --------------------------------------------------------------------------------