├── Infinite-CollectionViewGrid-Swift.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── ekscrypto.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Infinite-CollectionViewGrid-Swift ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── GridCoordinates.swift ├── InfiniteGrid.swift ├── InfiniteGridCell.swift ├── InfiniteGridDataSource.swift ├── InfiniteGridDelegate.swift ├── InfiniteGridLayout.swift ├── Info.plist └── ViewController.swift ├── LICENSE └── README.md /Infinite-CollectionViewGrid-Swift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 78B7895C212BD0DA00376761 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B7895B212BD0DA00376761 /* AppDelegate.swift */; }; 11 | 78B7895E212BD0DA00376761 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B7895D212BD0DA00376761 /* ViewController.swift */; }; 12 | 78B78961212BD0DA00376761 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78B7895F212BD0DA00376761 /* Main.storyboard */; }; 13 | 78B78963212BD0DB00376761 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 78B78962212BD0DB00376761 /* Assets.xcassets */; }; 14 | 78B78966212BD0DB00376761 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78B78964212BD0DB00376761 /* LaunchScreen.storyboard */; }; 15 | 78B7896E212BD31100376761 /* InfiniteGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B7896D212BD31100376761 /* InfiniteGrid.swift */; }; 16 | 78B78970212BD3C500376761 /* GridCoordinates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B7896F212BD3C500376761 /* GridCoordinates.swift */; }; 17 | 78B78972212BD3E400376761 /* InfiniteGridCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B78971212BD3E400376761 /* InfiniteGridCell.swift */; }; 18 | 78B78974212BD41900376761 /* InfiniteGridDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B78973212BD41900376761 /* InfiniteGridDataSource.swift */; }; 19 | 78B78976212BD47E00376761 /* InfiniteGridLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B78975212BD47E00376761 /* InfiniteGridLayout.swift */; }; 20 | 78B78978212BD5B600376761 /* InfiniteGridDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B78977212BD5B600376761 /* InfiniteGridDelegate.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 78B78958212BD0DA00376761 /* Infinite-CollectionViewGrid-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Infinite-CollectionViewGrid-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 78B7895B212BD0DA00376761 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 26 | 78B7895D212BD0DA00376761 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 27 | 78B78960212BD0DA00376761 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 28 | 78B78962212BD0DB00376761 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 29 | 78B78965212BD0DB00376761 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 30 | 78B78967212BD0DB00376761 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | 78B7896D212BD31100376761 /* InfiniteGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteGrid.swift; sourceTree = ""; }; 32 | 78B7896F212BD3C500376761 /* GridCoordinates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridCoordinates.swift; sourceTree = ""; }; 33 | 78B78971212BD3E400376761 /* InfiniteGridCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteGridCell.swift; sourceTree = ""; }; 34 | 78B78973212BD41900376761 /* InfiniteGridDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteGridDataSource.swift; sourceTree = ""; }; 35 | 78B78975212BD47E00376761 /* InfiniteGridLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteGridLayout.swift; sourceTree = ""; }; 36 | 78B78977212BD5B600376761 /* InfiniteGridDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteGridDelegate.swift; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | 78B78955212BD0DA00376761 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | /* End PBXFrameworksBuildPhase section */ 48 | 49 | /* Begin PBXGroup section */ 50 | 78B7894F212BD0DA00376761 = { 51 | isa = PBXGroup; 52 | children = ( 53 | 78B7895A212BD0DA00376761 /* Infinite-CollectionViewGrid-Swift */, 54 | 78B78959212BD0DA00376761 /* Products */, 55 | ); 56 | sourceTree = ""; 57 | }; 58 | 78B78959212BD0DA00376761 /* Products */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 78B78958212BD0DA00376761 /* Infinite-CollectionViewGrid-Swift.app */, 62 | ); 63 | name = Products; 64 | sourceTree = ""; 65 | }; 66 | 78B7895A212BD0DA00376761 /* Infinite-CollectionViewGrid-Swift */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 78B7895B212BD0DA00376761 /* AppDelegate.swift */, 70 | 78B7895D212BD0DA00376761 /* ViewController.swift */, 71 | 78B7896F212BD3C500376761 /* GridCoordinates.swift */, 72 | 78B7896D212BD31100376761 /* InfiniteGrid.swift */, 73 | 78B78971212BD3E400376761 /* InfiniteGridCell.swift */, 74 | 78B78973212BD41900376761 /* InfiniteGridDataSource.swift */, 75 | 78B78977212BD5B600376761 /* InfiniteGridDelegate.swift */, 76 | 78B78975212BD47E00376761 /* InfiniteGridLayout.swift */, 77 | 78B7895F212BD0DA00376761 /* Main.storyboard */, 78 | 78B78962212BD0DB00376761 /* Assets.xcassets */, 79 | 78B78964212BD0DB00376761 /* LaunchScreen.storyboard */, 80 | 78B78967212BD0DB00376761 /* Info.plist */, 81 | ); 82 | path = "Infinite-CollectionViewGrid-Swift"; 83 | sourceTree = ""; 84 | }; 85 | /* End PBXGroup section */ 86 | 87 | /* Begin PBXNativeTarget section */ 88 | 78B78957212BD0DA00376761 /* Infinite-CollectionViewGrid-Swift */ = { 89 | isa = PBXNativeTarget; 90 | buildConfigurationList = 78B7896A212BD0DB00376761 /* Build configuration list for PBXNativeTarget "Infinite-CollectionViewGrid-Swift" */; 91 | buildPhases = ( 92 | 78B78954212BD0DA00376761 /* Sources */, 93 | 78B78955212BD0DA00376761 /* Frameworks */, 94 | 78B78956212BD0DA00376761 /* Resources */, 95 | ); 96 | buildRules = ( 97 | ); 98 | dependencies = ( 99 | ); 100 | name = "Infinite-CollectionViewGrid-Swift"; 101 | productName = "Infinite-CollectionViewGrid-Swift"; 102 | productReference = 78B78958212BD0DA00376761 /* Infinite-CollectionViewGrid-Swift.app */; 103 | productType = "com.apple.product-type.application"; 104 | }; 105 | /* End PBXNativeTarget section */ 106 | 107 | /* Begin PBXProject section */ 108 | 78B78950212BD0DA00376761 /* Project object */ = { 109 | isa = PBXProject; 110 | attributes = { 111 | LastSwiftUpdateCheck = 1000; 112 | LastUpgradeCheck = 1000; 113 | ORGANIZATIONNAME = "ID Fusion Software Inc"; 114 | TargetAttributes = { 115 | 78B78957212BD0DA00376761 = { 116 | CreatedOnToolsVersion = 10.0; 117 | }; 118 | }; 119 | }; 120 | buildConfigurationList = 78B78953212BD0DA00376761 /* Build configuration list for PBXProject "Infinite-CollectionViewGrid-Swift" */; 121 | compatibilityVersion = "Xcode 9.3"; 122 | developmentRegion = en; 123 | hasScannedForEncodings = 0; 124 | knownRegions = ( 125 | en, 126 | Base, 127 | ); 128 | mainGroup = 78B7894F212BD0DA00376761; 129 | productRefGroup = 78B78959212BD0DA00376761 /* Products */; 130 | projectDirPath = ""; 131 | projectRoot = ""; 132 | targets = ( 133 | 78B78957212BD0DA00376761 /* Infinite-CollectionViewGrid-Swift */, 134 | ); 135 | }; 136 | /* End PBXProject section */ 137 | 138 | /* Begin PBXResourcesBuildPhase section */ 139 | 78B78956212BD0DA00376761 /* Resources */ = { 140 | isa = PBXResourcesBuildPhase; 141 | buildActionMask = 2147483647; 142 | files = ( 143 | 78B78966212BD0DB00376761 /* LaunchScreen.storyboard in Resources */, 144 | 78B78963212BD0DB00376761 /* Assets.xcassets in Resources */, 145 | 78B78961212BD0DA00376761 /* Main.storyboard in Resources */, 146 | ); 147 | runOnlyForDeploymentPostprocessing = 0; 148 | }; 149 | /* End PBXResourcesBuildPhase section */ 150 | 151 | /* Begin PBXSourcesBuildPhase section */ 152 | 78B78954212BD0DA00376761 /* Sources */ = { 153 | isa = PBXSourcesBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | 78B78976212BD47E00376761 /* InfiniteGridLayout.swift in Sources */, 157 | 78B7896E212BD31100376761 /* InfiniteGrid.swift in Sources */, 158 | 78B78970212BD3C500376761 /* GridCoordinates.swift in Sources */, 159 | 78B78974212BD41900376761 /* InfiniteGridDataSource.swift in Sources */, 160 | 78B78978212BD5B600376761 /* InfiniteGridDelegate.swift in Sources */, 161 | 78B7895E212BD0DA00376761 /* ViewController.swift in Sources */, 162 | 78B7895C212BD0DA00376761 /* AppDelegate.swift in Sources */, 163 | 78B78972212BD3E400376761 /* InfiniteGridCell.swift in Sources */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXSourcesBuildPhase section */ 168 | 169 | /* Begin PBXVariantGroup section */ 170 | 78B7895F212BD0DA00376761 /* Main.storyboard */ = { 171 | isa = PBXVariantGroup; 172 | children = ( 173 | 78B78960212BD0DA00376761 /* Base */, 174 | ); 175 | name = Main.storyboard; 176 | sourceTree = ""; 177 | }; 178 | 78B78964212BD0DB00376761 /* LaunchScreen.storyboard */ = { 179 | isa = PBXVariantGroup; 180 | children = ( 181 | 78B78965212BD0DB00376761 /* Base */, 182 | ); 183 | name = LaunchScreen.storyboard; 184 | sourceTree = ""; 185 | }; 186 | /* End PBXVariantGroup section */ 187 | 188 | /* Begin XCBuildConfiguration section */ 189 | 78B78968212BD0DB00376761 /* Debug */ = { 190 | isa = XCBuildConfiguration; 191 | buildSettings = { 192 | ALWAYS_SEARCH_USER_PATHS = NO; 193 | CLANG_ANALYZER_NONNULL = YES; 194 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 195 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 196 | CLANG_CXX_LIBRARY = "libc++"; 197 | CLANG_ENABLE_MODULES = YES; 198 | CLANG_ENABLE_OBJC_ARC = YES; 199 | CLANG_ENABLE_OBJC_WEAK = YES; 200 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 201 | CLANG_WARN_BOOL_CONVERSION = YES; 202 | CLANG_WARN_COMMA = YES; 203 | CLANG_WARN_CONSTANT_CONVERSION = YES; 204 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 205 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 206 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 207 | CLANG_WARN_EMPTY_BODY = YES; 208 | CLANG_WARN_ENUM_CONVERSION = YES; 209 | CLANG_WARN_INFINITE_RECURSION = YES; 210 | CLANG_WARN_INT_CONVERSION = YES; 211 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 212 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 213 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 215 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 216 | CLANG_WARN_STRICT_PROTOTYPES = YES; 217 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 218 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 219 | CLANG_WARN_UNREACHABLE_CODE = YES; 220 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 221 | CODE_SIGN_IDENTITY = "iPhone Developer"; 222 | COPY_PHASE_STRIP = NO; 223 | DEBUG_INFORMATION_FORMAT = dwarf; 224 | ENABLE_STRICT_OBJC_MSGSEND = YES; 225 | ENABLE_TESTABILITY = YES; 226 | GCC_C_LANGUAGE_STANDARD = gnu11; 227 | GCC_DYNAMIC_NO_PIC = NO; 228 | GCC_NO_COMMON_BLOCKS = YES; 229 | GCC_OPTIMIZATION_LEVEL = 0; 230 | GCC_PREPROCESSOR_DEFINITIONS = ( 231 | "DEBUG=1", 232 | "$(inherited)", 233 | ); 234 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 235 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 236 | GCC_WARN_UNDECLARED_SELECTOR = YES; 237 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 238 | GCC_WARN_UNUSED_FUNCTION = YES; 239 | GCC_WARN_UNUSED_VARIABLE = YES; 240 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 241 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 242 | MTL_FAST_MATH = YES; 243 | ONLY_ACTIVE_ARCH = YES; 244 | SDKROOT = iphoneos; 245 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 246 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 247 | }; 248 | name = Debug; 249 | }; 250 | 78B78969212BD0DB00376761 /* Release */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ALWAYS_SEARCH_USER_PATHS = NO; 254 | CLANG_ANALYZER_NONNULL = YES; 255 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 256 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 257 | CLANG_CXX_LIBRARY = "libc++"; 258 | CLANG_ENABLE_MODULES = YES; 259 | CLANG_ENABLE_OBJC_ARC = YES; 260 | CLANG_ENABLE_OBJC_WEAK = YES; 261 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 262 | CLANG_WARN_BOOL_CONVERSION = YES; 263 | CLANG_WARN_COMMA = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 266 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 267 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 268 | CLANG_WARN_EMPTY_BODY = YES; 269 | CLANG_WARN_ENUM_CONVERSION = YES; 270 | CLANG_WARN_INFINITE_RECURSION = YES; 271 | CLANG_WARN_INT_CONVERSION = YES; 272 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 273 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 274 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 276 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 277 | CLANG_WARN_STRICT_PROTOTYPES = YES; 278 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 279 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 280 | CLANG_WARN_UNREACHABLE_CODE = YES; 281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 282 | CODE_SIGN_IDENTITY = "iPhone Developer"; 283 | COPY_PHASE_STRIP = NO; 284 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 285 | ENABLE_NS_ASSERTIONS = NO; 286 | ENABLE_STRICT_OBJC_MSGSEND = YES; 287 | GCC_C_LANGUAGE_STANDARD = gnu11; 288 | GCC_NO_COMMON_BLOCKS = YES; 289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 291 | GCC_WARN_UNDECLARED_SELECTOR = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 293 | GCC_WARN_UNUSED_FUNCTION = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 296 | MTL_ENABLE_DEBUG_INFO = NO; 297 | MTL_FAST_MATH = YES; 298 | SDKROOT = iphoneos; 299 | SWIFT_COMPILATION_MODE = wholemodule; 300 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 301 | VALIDATE_PRODUCT = YES; 302 | }; 303 | name = Release; 304 | }; 305 | 78B7896B212BD0DB00376761 /* Debug */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 309 | CODE_SIGN_STYLE = Automatic; 310 | DEVELOPMENT_TEAM = DU44C6AG9P; 311 | INFOPLIST_FILE = "Infinite-CollectionViewGrid-Swift/Info.plist"; 312 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 313 | LD_RUNPATH_SEARCH_PATHS = ( 314 | "$(inherited)", 315 | "@executable_path/Frameworks", 316 | ); 317 | PRODUCT_BUNDLE_IDENTIFIER = "com.idfusion.Infinite-CollectionViewGrid-Swift"; 318 | PRODUCT_NAME = "$(TARGET_NAME)"; 319 | SWIFT_VERSION = 4.1; 320 | TARGETED_DEVICE_FAMILY = "1,2"; 321 | }; 322 | name = Debug; 323 | }; 324 | 78B7896C212BD0DB00376761 /* Release */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 328 | CODE_SIGN_STYLE = Automatic; 329 | DEVELOPMENT_TEAM = DU44C6AG9P; 330 | INFOPLIST_FILE = "Infinite-CollectionViewGrid-Swift/Info.plist"; 331 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 332 | LD_RUNPATH_SEARCH_PATHS = ( 333 | "$(inherited)", 334 | "@executable_path/Frameworks", 335 | ); 336 | PRODUCT_BUNDLE_IDENTIFIER = "com.idfusion.Infinite-CollectionViewGrid-Swift"; 337 | PRODUCT_NAME = "$(TARGET_NAME)"; 338 | SWIFT_VERSION = 4.1; 339 | TARGETED_DEVICE_FAMILY = "1,2"; 340 | }; 341 | name = Release; 342 | }; 343 | /* End XCBuildConfiguration section */ 344 | 345 | /* Begin XCConfigurationList section */ 346 | 78B78953212BD0DA00376761 /* Build configuration list for PBXProject "Infinite-CollectionViewGrid-Swift" */ = { 347 | isa = XCConfigurationList; 348 | buildConfigurations = ( 349 | 78B78968212BD0DB00376761 /* Debug */, 350 | 78B78969212BD0DB00376761 /* Release */, 351 | ); 352 | defaultConfigurationIsVisible = 0; 353 | defaultConfigurationName = Release; 354 | }; 355 | 78B7896A212BD0DB00376761 /* Build configuration list for PBXNativeTarget "Infinite-CollectionViewGrid-Swift" */ = { 356 | isa = XCConfigurationList; 357 | buildConfigurations = ( 358 | 78B7896B212BD0DB00376761 /* Debug */, 359 | 78B7896C212BD0DB00376761 /* Release */, 360 | ); 361 | defaultConfigurationIsVisible = 0; 362 | defaultConfigurationName = Release; 363 | }; 364 | /* End XCConfigurationList section */ 365 | }; 366 | rootObject = 78B78950212BD0DA00376761 /* Project object */; 367 | } 368 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift.xcodeproj/xcuserdata/ekscrypto.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Infinite-CollectionViewGrid-Swift.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Infinite-CollectionViewGrid-Swift 4 | // 5 | // Created by Dave Poirier for ID Fusion Software Inc on 2018-08-20. 6 | // This is free and unencumbered software released into the public domain. 7 | // 8 | // For countries not supporting unlicensed code: 9 | // Copyright (C) 2018 ID Fusion Software Inc. All rights reserved 10 | // Distributed under the MIT License: https://opensource.org/licenses/MIT 11 | 12 | import UIKit 13 | 14 | @UIApplicationMain 15 | class AppDelegate: UIResponder, UIApplicationDelegate { 16 | 17 | var window: UIWindow? 18 | 19 | func application(_ application: UIApplication, 20 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) 21 | -> Bool { 22 | 23 | return true 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/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 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/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 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/GridCoordinates.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GridCoordinates.swift 3 | // Infinite-CollectionViewGrid-Swift 4 | // 5 | // Created by Dave Poirier for ID Fusion Software Inc on 2018-08-20. 6 | // This is free and unencumbered software released into the public domain. 7 | // 8 | // For countries not supporting unlicensed code: 9 | // Copyright (C) 2018 ID Fusion Software Inc. All rights reserved 10 | // Distributed under the MIT License: https://opensource.org/licenses/MIT 11 | 12 | import Foundation 13 | struct GridCoordinates: Equatable { 14 | let x: Int 15 | let y: Int 16 | } 17 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/InfiniteGrid.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfiniteGrid.swift 3 | // Infinite-CollectionViewGrid-Swift 4 | // 5 | // Created by Dave Poirier for ID Fusion Software Inc on 2018-08-20. 6 | // This is free and unencumbered software released into the public domain. 7 | // 8 | // For countries not supporting unlicensed code: 9 | // Copyright (C) 2018 ID Fusion Software Inc. All rights reserved 10 | // Distributed under the MIT License: https://opensource.org/licenses/MIT 11 | 12 | import UIKit 13 | class InfiniteGrid: UICollectionView { 14 | 15 | let infiniteDataSource = InfiniteGridDataSource() 16 | let infiniteDelegate = InfiniteGridDelegate() 17 | var centerCoordinates = GridCoordinates(x: 0, y: 0) { 18 | didSet { self.reloadData() } 19 | } 20 | 21 | convenience init(hostView: UIView) { 22 | self.init(frame: hostView.bounds, collectionViewLayout: InfiniteGridLayout()) 23 | self.autoresizingMask = [.flexibleWidth, .flexibleHeight] 24 | self.translatesAutoresizingMaskIntoConstraints = true 25 | self.backgroundColor = UIColor.clear 26 | self.dataSource = infiniteDataSource 27 | InfiniteGridCell.register(with: self) 28 | 29 | self.delegate = infiniteDelegate 30 | infiniteDelegate.grid = self 31 | infiniteDelegate.layout = self.collectionViewLayout as? InfiniteGridLayout 32 | 33 | hostView.addSubview(self) 34 | } 35 | 36 | func scrollToCenter() { 37 | let size = self.contentSize 38 | let topLeftCoordinatesWhenCentered = CGPoint(x: (size.width - self.frame.width) * 0.5, 39 | y: (size.height - self.frame.height) * 0.5) 40 | self.setContentOffset(topLeftCoordinatesWhenCentered, animated: false) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/InfiniteGridCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfiniteGridCell.swift 3 | // Infinite-CollectionViewGrid-Swift 4 | // 5 | // Created by Dave Poirier for ID Fusion Software Inc on 2018-08-20. 6 | // This is free and unencumbered software released into the public domain. 7 | // 8 | // For countries not supporting unlicensed code: 9 | // Copyright (C) 2018 ID Fusion Software Inc. All rights reserved 10 | // Distributed under the MIT License: https://opensource.org/licenses/MIT 11 | 12 | import UIKit 13 | class InfiniteGridCell: UICollectionViewCell { 14 | 15 | private(set) var coordinates = GridCoordinates(x: 0, y: 0) { 16 | didSet { coordinatesLabel().text = "\(coordinates.x), \(coordinates.y)" } 17 | } 18 | 19 | static let identifier = "InfiniteGridCell" 20 | static func register(with collectionView: UICollectionView) { 21 | collectionView.register(self, forCellWithReuseIdentifier: identifier) 22 | } 23 | 24 | static func dequeue(from collectionView: UICollectionView, 25 | at indexPath: IndexPath, 26 | for coordinates: GridCoordinates) 27 | -> InfiniteGridCell { 28 | 29 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) 30 | as? InfiniteGridCell ?? InfiniteGridCell() 31 | cell.coordinates = coordinates 32 | return cell 33 | } 34 | 35 | private func coordinatesLabel() 36 | -> UILabel { 37 | 38 | if let label = self.contentView.subviews.first as? UILabel { 39 | return label 40 | } 41 | 42 | let label = UILabel(frame: self.contentView.bounds) 43 | label.font = UIFont.systemFont(ofSize: 24.0) 44 | label.textColor = UIColor.darkGray 45 | label.textAlignment = .center 46 | label.minimumScaleFactor = 0.5 47 | label.adjustsFontSizeToFitWidth = true 48 | label.autoresizingMask = [.flexibleHeight, .flexibleWidth] 49 | label.translatesAutoresizingMaskIntoConstraints = true 50 | self.contentView.addSubview(label) 51 | return label 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/InfiniteGridDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfiniteGridDataSource.swift 3 | // Infinite-CollectionViewGrid-Swift 4 | // 5 | // Created by Dave Poirier for ID Fusion Software Inc on 2018-08-20. 6 | // This is free and unencumbered software released into the public domain. 7 | // 8 | // For countries not supporting unlicensed code: 9 | // Copyright (C) 2018 ID Fusion Software Inc. All rights reserved 10 | // Distributed under the MIT License: https://opensource.org/licenses/MIT 11 | 12 | import UIKit 13 | class InfiniteGridDataSource: NSObject, UICollectionViewDataSource { 14 | 15 | // arbitrary large number, increase if you use small tile sizes and some cells are not appearing when scrolling 16 | let pathsCacheSize: Int = 1024 17 | 18 | var pathsCache: [IndexPath: GridCoordinates] = [:] 19 | var pathsCacheIndex: Int = 0 20 | 21 | func numberOfSections(in collectionView: UICollectionView) 22 | -> Int { 23 | 24 | return 1 25 | } 26 | 27 | func collectionView(_ collectionView: UICollectionView, 28 | numberOfItemsInSection section: Int) 29 | -> Int { 30 | 31 | return pathsCacheSize 32 | } 33 | 34 | func collectionView(_ collectionView: UICollectionView, 35 | cellForItemAt indexPath: IndexPath) 36 | -> UICollectionViewCell { 37 | 38 | let coordinates = pathsCache[indexPath] ?? GridCoordinates(x: 0, y: 0) 39 | return InfiniteGridCell.dequeue(from: collectionView, at: indexPath, for: coordinates) 40 | } 41 | 42 | func assignPath(to coordinates: GridCoordinates) 43 | -> IndexPath { 44 | 45 | for cacheEntry in pathsCache where cacheEntry.value == coordinates { 46 | return cacheEntry.key 47 | } 48 | 49 | let indexPath = IndexPath(item: pathsCacheIndex, section: 0) 50 | pathsCacheIndex = (pathsCacheIndex + 1) % pathsCacheSize 51 | pathsCache[indexPath] = coordinates 52 | return indexPath 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/InfiniteGridDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfiniteGridDelegate.swift 3 | // Infinite-CollectionViewGrid-Swift 4 | // 5 | // Created by Dave Poirier on 2018-08-21. 6 | // Copyright © 2018 ID Fusion Software Inc. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class InfiniteGridDelegate: NSObject, UIScrollViewDelegate, UICollectionViewDelegate { 12 | 13 | weak var grid: InfiniteGrid? 14 | weak var layout: InfiniteGridLayout? 15 | 16 | private var expectingEndDecelarationEvent: Bool = false 17 | 18 | func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { 19 | guard decelerate == false else { 20 | expectingEndDecelarationEvent = true 21 | return 22 | } 23 | expectingEndDecelarationEvent = false 24 | self.readjustOffsets() 25 | } 26 | 27 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { 28 | guard expectingEndDecelarationEvent else { return } 29 | expectingEndDecelarationEvent = false 30 | self.readjustOffsets() 31 | } 32 | 33 | private func readjustOffsets() { 34 | guard let layout = self.layout else { return } 35 | 36 | let displacement = layout.gridCenterDisplacement() 37 | let (horizontalTiles, verticalTiles) = layout.roundToTiles(distance: displacement, rounding: .towardZero) 38 | adjustContentOffsetBy(horizontalTiles, verticalTiles) 39 | } 40 | 41 | private func adjustContentOffsetBy(_ horizontalTiles: CGFloat, _ verticalTiles: CGFloat) { 42 | guard 43 | let tileSize = self.layout?.tileSize, 44 | let grid = self.grid, 45 | horizontalTiles != 0 || verticalTiles != 0 46 | else { return } 47 | 48 | let updatedOffset = CGPoint(x: grid.contentOffset.x - (horizontalTiles * tileSize.width), 49 | y: grid.contentOffset.y - (verticalTiles * tileSize.height)) 50 | grid.setContentOffset(updatedOffset, animated: false) 51 | grid.centerCoordinates = GridCoordinates(x: grid.centerCoordinates.x + Int(horizontalTiles), 52 | y: grid.centerCoordinates.y + Int(verticalTiles)) 53 | // reloadData() performed by didSet of centerCoordinates 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/InfiniteGridLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfiniteGridLayout.swift 3 | // Infinite-CollectionViewGrid-Swift 4 | // 5 | // Created by Dave Poirier for ID Fusion Software Inc on 2018-08-20. 6 | // This is free and unencumbered software released into the public domain. 7 | // 8 | // For countries not supporting unlicensed code: 9 | // Copyright (C) 2018 ID Fusion Software Inc. All rights reserved 10 | // Distributed under the MIT License: https://opensource.org/licenses/MIT 11 | 12 | import UIKit 13 | class InfiniteGridLayout: UICollectionViewLayout { 14 | 15 | let gridSize = CGSize(width: 10000000.0, height: 10000000.0) // arbitrary size - something very large 16 | let tileSize = CGSize(width: 100.0, height: 100.0) // arbitrary size 17 | 18 | override var collectionViewContentSize: CGSize { 19 | return gridSize 20 | } 21 | 22 | override func layoutAttributesForElements(in rect: CGRect) 23 | -> [UICollectionViewLayoutAttributes]? { 24 | 25 | let topLeftCoordinates = coordinates(at: CGPoint(x: rect.minX, y: rect.minY)) 26 | let bottomRightCoordinates = coordinates(at: CGPoint(x: rect.maxX, y: rect.maxY)) 27 | return layoutAttributes(from: topLeftCoordinates, to: bottomRightCoordinates) 28 | } 29 | 30 | override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 31 | // Not supported 32 | return nil 33 | } 34 | 35 | private func layoutAttributes(from topLeftCoordinates: GridCoordinates, 36 | to bottomRightCoordinates: GridCoordinates) 37 | -> [UICollectionViewLayoutAttributes]? { 38 | 39 | guard 40 | let grid = self.collectionView as? InfiniteGrid, 41 | let dataSource = grid.dataSource as? InfiniteGridDataSource 42 | else { return nil } 43 | 44 | var attributes: [UICollectionViewLayoutAttributes] = [] 45 | for xCoordinate in topLeftCoordinates.x ... bottomRightCoordinates.x { 46 | for yCoordinate in topLeftCoordinates.y ... bottomRightCoordinates.y { 47 | let coordinates = GridCoordinates(x: xCoordinate, y: yCoordinate) 48 | attributes.append(layoutAttributes(for: coordinates, using: dataSource)) 49 | } 50 | } 51 | return attributes 52 | } 53 | 54 | private func layoutAttributes(for coordinates: GridCoordinates, 55 | using dataSource: InfiniteGridDataSource) 56 | -> UICollectionViewLayoutAttributes { 57 | 58 | let indexPath = dataSource.assignPath(to: coordinates) 59 | let layoutAttributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) 60 | layoutAttributes.frame = CGRect(origin: originForTile(at: coordinates), 61 | size: tileSize) 62 | return layoutAttributes 63 | } 64 | 65 | func coordinates(at point: CGPoint) 66 | -> GridCoordinates { 67 | 68 | guard 69 | let centerCoordinates = (self.collectionView as? InfiniteGrid)?.centerCoordinates 70 | else { return GridCoordinates(x: 0, y: 0) } 71 | 72 | let centerTileOffset = gridCenterTileOffset() 73 | let distance = (point.x - centerTileOffset.x, point.y - centerTileOffset.y) 74 | let (horizontalTiles, verticalTiles) = roundToTiles(distance: distance, rounding: .awayFromZero) 75 | return GridCoordinates(x: centerCoordinates.x + Int(horizontalTiles), 76 | y: centerCoordinates.y + Int(verticalTiles)) 77 | } 78 | 79 | private func gridCenterTileOffset() 80 | -> CGPoint { 81 | return CGPoint(x: (gridSize.width - tileSize.width) * 0.5, 82 | y: (gridSize.height - tileSize.height) * 0.5) 83 | } 84 | 85 | private func originForTile(at coordinates: GridCoordinates) 86 | -> CGPoint { 87 | 88 | guard 89 | let centerCoordinates = (self.collectionView as? InfiniteGrid)?.centerCoordinates 90 | else { return CGPoint.zero } 91 | 92 | let centerTileOffset = gridCenterTileOffset() 93 | return CGPoint(x: centerTileOffset.x + tileSize.width * CGFloat(coordinates.x - centerCoordinates.x), 94 | y: centerTileOffset.y + tileSize.height * CGFloat(coordinates.y - centerCoordinates.y)) 95 | } 96 | 97 | func gridCenterDisplacement() 98 | -> (CGFloat, CGFloat) { 99 | 100 | guard 101 | let grid = self.collectionView as? InfiniteGrid 102 | else { return (0, 0) } 103 | 104 | let contentOffset = grid.contentOffset 105 | let visibleSize = grid.frame.size 106 | return (contentOffset.x - (gridSize.width - visibleSize.width) * 0.5, 107 | contentOffset.y - (gridSize.height - visibleSize.height) * 0.5) 108 | } 109 | 110 | func roundToTiles(distance: (CGFloat, CGFloat), 111 | rounding roundingRule: FloatingPointRoundingRule) 112 | -> (CGFloat, CGFloat) { 113 | 114 | guard tileSize.width > 0, 115 | tileSize.height > 0 116 | else { return (0, 0) } 117 | 118 | let (horizontal, vertical) = distance 119 | return ((horizontal / tileSize.width).rounded(roundingRule), 120 | (vertical / tileSize.height).rounded(roundingRule)) 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Infinite-CollectionViewGrid-Swift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Infinite-CollectionViewGrid-Swift 4 | // 5 | // Created by Dave Poirier for ID Fusion Software Inc on 2018-08-20. 6 | // This is free and unencumbered software released into the public domain. 7 | // 8 | // For countries not supporting unlicensed code: 9 | // Copyright (C) 2018 ID Fusion Software Inc. All rights reserved 10 | // Distributed under the MIT License: https://opensource.org/licenses/MIT 11 | 12 | import UIKit 13 | class ViewController: UIViewController { 14 | 15 | var infiniteGrid: InfiniteGrid? 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | // Do any additional setup after loading the view, typically from a nib. 20 | self.infiniteGrid = InfiniteGrid(hostView: self.view) 21 | } 22 | 23 | override func viewDidAppear(_ animated: Bool) { 24 | super.viewDidAppear(animated) 25 | 26 | infiniteGrid?.scrollToCenter() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This code is dual license. 2 | 3 | For countries supporting unlicensed code: 4 | ------ 5 | This is free and unencumbered software released into the public domain. 6 | 7 | Anyone is free to copy, modify, publish, use, compile, sell, or 8 | distribute this software, either in source code form or as a compiled 9 | binary, for any purpose, commercial or non-commercial, and by any 10 | means. 11 | 12 | In jurisdictions that recognize copyright laws, the author or authors 13 | of this software dedicate any and all copyright interest in the 14 | software to the public domain. We make this dedication for the benefit 15 | of the public at large and to the detriment of our heirs and 16 | successors. We intend this dedication to be an overt act of 17 | relinquishment in perpetuity of all present and future rights to this 18 | software under copyright law. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | For more information, please refer to 29 | ------ 30 | 31 | 32 | 33 | For countries without support for unlicensed code, please use the MIT License below: 34 | ------ 35 | Copyright 2018 ID Fusion Software Inc 36 | 37 | Permission is hereby granted, free of charge, to any person obtaining 38 | a copy of this software and associated documentation files (the 39 | "Software"), to deal in the Software without restriction, including 40 | without limitation the rights to use, copy, modify, merge, publish, 41 | distribute, sublicense, and/or sell copies of the Software, and to 42 | permit persons to whom the Software is furnished to do so, subject 43 | to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be included 46 | in all copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 49 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 50 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 51 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 52 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 53 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 54 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 55 | ------ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Infinite-CollectionViewGrid-Swift 2 | Sample repository on how to create an infinite grid using native UIKit components. This repository contains commits at the various stage of the tutorial on Medium.com located at: https://medium.com/@davepoirier/infinite-grid-using-uicollectionview-155801e4f7f4 3 | 4 | ## About the author 5 | 6 | Dave Poirier is a senior software developer, currently working on creating some really interesting iOS applications at ID Fusion Software Inc. 7 | 8 | Need help with your mobile app software development? Visit our website at http://idfusion.com 9 | --------------------------------------------------------------------------------