├── Default-568h@2x.png
├── Example
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AppDelegate.swift
├── InfoExample.plist
├── ViewController.swift
└── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
├── BSGridCollectionViewLayout.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ ├── Tests.xcscheme
│ │ └── BSGridCollectionViewLayout.xcscheme
└── project.pbxproj
├── .travis.yml
├── Sources
├── BSGridCollectionViewLayout.h
├── InfoSource.plist
└── GridCollectionViewLayout.swift
├── .gitignore
├── BSGridCollectionViewLayout.podspec
├── Tests
├── Tests.swift
├── FirstIndexTests.swift
├── LastIndexTests.swift
├── FirstRowTests.swift
└── LastRowTests.swift
├── LICENSE
└── README.md
/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikaoj/BSGridCollectionViewLayout/HEAD/Default-568h@2x.png
--------------------------------------------------------------------------------
/Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/BSGridCollectionViewLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BSGridCollectionViewLayout.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # references:
2 | # * http://www.objc.io/issue-6/travis-ci.html
3 | # * https://github.com/supermarin/xcpretty#usage
4 |
5 | osx_image: xcode7.3
6 | language: objective-c
7 | #cache: cocoapods
8 | podfile: Example/Podfile
9 | before_install:
10 | - gem install cocoapods # Since Travis is not always on latest version
11 | #- pod install --project-directory=Example
12 | install:
13 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
14 | script:
15 | - set -o pipefail && xcodebuild test -workspace Example/BSGridCollectionViewLayout.xcworkspace -scheme BSGridCollectionViewLayout-Example -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty -c
16 | - pod lib lint --quick
17 |
--------------------------------------------------------------------------------
/Sources/BSGridCollectionViewLayout.h:
--------------------------------------------------------------------------------
1 | //
2 | // BSGridCollectionViewLayout.h
3 | // BSGridCollectionViewLayout
4 | //
5 | // Created by Joakim Gyllström on 2018-12-27.
6 | // Copyright © 2018 Joakim Gyllström. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for BSGridCollectionViewLayout.
12 | FOUNDATION_EXPORT double BSGridCollectionViewLayoutVersionNumber;
13 |
14 | //! Project version string for BSGridCollectionViewLayout.
15 | FOUNDATION_EXPORT const unsigned char BSGridCollectionViewLayoutVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata
15 | *.xccheckout
16 | profile
17 | *.moved-aside
18 | DerivedData
19 | *.hmap
20 | *.ipa
21 |
22 | # Bundler
23 | .bundle
24 |
25 | Carthage
26 | # We recommend against adding the Pods directory to your .gitignore. However
27 | # you should judge for yourself, the pros and cons are mentioned at:
28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
29 | #
30 | # Note: if you ignore the Pods directory, make sure to uncomment
31 | # `pod install` in .travis.yml
32 | #
33 | # Pods/
34 |
--------------------------------------------------------------------------------
/Sources/InfoSource.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 | FMWK
17 | CFBundleShortVersionString
18 | 1.2.5
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BSGridCollectionViewLayout.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "BSGridCollectionViewLayout"
3 | s.version = "1.2.5"
4 | s.summary = "Simple grid collection view layout."
5 | s.description = <<-DESC
6 | A simple grid collection view layout. Displays multiple sections as one continuous grid without any section breaks.
7 | DESC
8 |
9 | s.homepage = "https://github.com/mikaoj/BSGridCollectionViewLayout"
10 | s.license = 'MIT'
11 | s.author = { "Joakim Gyllstrom" => "joakim@backslashed.se" }
12 | s.swift_version = "5.0"
13 | s.source = { :git => "https://github.com/mikaoj/BSGridCollectionViewLayout.git", :tag => s.version.to_s }
14 | s.platform = :ios, '8.0'
15 | s.requires_arc = true
16 |
17 | s.source_files = 'Sources/**/*.{swift,h}'
18 | end
19 |
--------------------------------------------------------------------------------
/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Tests.swift
3 | // Tests
4 | //
5 | // Created by Joakim Gyllström on 2018-12-27.
6 | // Copyright © 2018 Joakim Gyllström. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class Tests: XCTestCase {
12 |
13 | override func setUp() {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 | }
16 |
17 | override func tearDown() {
18 | // Put teardown code here. This method is called after the invocation of each test method in the class.
19 | }
20 |
21 | func testExample() {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | }
25 |
26 | func testPerformanceExample() {
27 | // This is an example of a performance test case.
28 | self.measure {
29 | // Put the code you want to measure the time of here.
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Joakim Gyllstrom
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Joakim Gyllström
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import UIKit
24 |
25 | @UIApplicationMain
26 | class AppDelegate: UIResponder, UIApplicationDelegate {
27 |
28 | var window: UIWindow?
29 |
30 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
31 | return true
32 | }
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/Example/InfoExample.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.2.3
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 |
--------------------------------------------------------------------------------
/Tests/FirstIndexTests.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2016 Joakim Gyllström
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import XCTest
24 | @testable import BSGridCollectionViewLayout
25 |
26 | class FirstIndexTests: XCTestCase {
27 | func testFirstIndexFirstRow() {
28 | let index = GridCollectionViewLayout.firstIndexInRow(0, withItemsPerRow: 3)
29 | XCTAssertEqual(index, 0)
30 | }
31 |
32 | func testFirstIndexThirdRow() {
33 | let index = GridCollectionViewLayout.firstIndexInRow(3, withItemsPerRow: 3)
34 | XCTAssertEqual(index, 9)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BSGridCollectionViewLayout
2 |
3 | [](https://travis-ci.org/mikaoj/BSGridCollectionViewLayout)
4 | [](http://cocoapods.org/pods/BSGridCollectionViewLayout)
5 | [](http://cocoapods.org/pods/BSGridCollectionViewLayout)
6 | [](http://cocoapods.org/pods/BSGridCollectionViewLayout)
7 |
8 | BSGridCollectionViewLayout is a simple UICollectionViewLayout. It simply displays the items in a grid. It doesn't have a concept of sections. So even if the items are in different data source / sections. They will be displayed as being in one continuous grid without any section breaks. I highly doubt that anyone besides me will use this, but I'm using it in [BSImagePicker](https://github.com/mikaoj/BSImagePicker).
9 |
10 | ## Usage
11 |
12 | There are 3 properties for you to tweak:
13 | * itemsPerRow - Number of items per row
14 | * itemSpacing - Spacing between items (vertical and horizontal)
15 | * itemHeightRatio - The item height ratio relative to it's width
16 |
17 | To run the example project, clone the repo, and run `pod install` from the Example directory first.
18 |
19 | ## Requirements
20 | iOS 8
21 |
22 | ## Installation
23 |
24 | BSGridCollectionViewLayout is available through [CocoaPods](http://cocoapods.org). To install
25 | it, simply add the following line to your Podfile:
26 |
27 | ```ruby
28 | pod "BSGridCollectionViewLayout", "~> 1.1.0"
29 | ```
30 |
31 | ## Author
32 |
33 | Joakim Gyllstrom, joakim@backslashed.se
34 |
35 | ## License
36 |
37 | BSGridCollectionViewLayout is available under the MIT license. See the LICENSE file for more info.
38 |
--------------------------------------------------------------------------------
/Example/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 | }
--------------------------------------------------------------------------------
/BSGridCollectionViewLayout.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
39 |
40 |
41 |
42 |
48 |
49 |
51 |
52 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Tests/LastIndexTests.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2016 Joakim Gyllström
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import XCTest
24 | @testable import BSGridCollectionViewLayout
25 |
26 | class LastIndexTests: XCTestCase {
27 | func testLastIndexFirstRowLowNumberOfItems() {
28 | let index = GridCollectionViewLayout.lastIndexInRow(0, withItemsPerRow: 3, numberOfItems: 2)
29 | XCTAssertEqual(index, 1)
30 | }
31 |
32 | func testLastIndexFirstRowMediumNumberOfItems() {
33 | let index = GridCollectionViewLayout.lastIndexInRow(0, withItemsPerRow: 3, numberOfItems: 6)
34 | XCTAssertEqual(index, 2)
35 | }
36 |
37 | func testLastIndexFirstRowLargeNumberOfItems() {
38 | let index = GridCollectionViewLayout.lastIndexInRow(0, withItemsPerRow: 3, numberOfItems: 500)
39 | XCTAssertEqual(index, 2)
40 | }
41 |
42 | func testLastIndexThirdRowLowNumberOfItems() {
43 | let index = GridCollectionViewLayout.lastIndexInRow(2, withItemsPerRow: 3, numberOfItems: 7)
44 | XCTAssertEqual(index, 6)
45 | }
46 |
47 | func testLastIndexThirdRowMediumNumberOfItems() {
48 | let index = GridCollectionViewLayout.lastIndexInRow(2, withItemsPerRow: 3, numberOfItems: 8)
49 | XCTAssertEqual(index, 7)
50 | }
51 |
52 | func testLastIndexThirdRowLargeNumberOfItems() {
53 | let index = GridCollectionViewLayout.lastIndexInRow(2, withItemsPerRow: 3, numberOfItems: 500)
54 | XCTAssertEqual(index, 8)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Tests/FirstRowTests.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2016 Joakim Gyllström
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import UIKit
24 | import XCTest
25 | @testable import BSGridCollectionViewLayout
26 |
27 | class FirstRowTests: XCTestCase {
28 |
29 | func testFirstRowInZeroRect() {
30 | let firstRow = GridCollectionViewLayout.firstRowInRect(CGRect.zero, withRowHeight: 100.0)
31 | XCTAssertEqual(firstRow, 0)
32 | }
33 |
34 | func testFirstRowWithoutOffset() {
35 | let firstRow = GridCollectionViewLayout.firstRowInRect(CGRect(x: 0, y: 0, width: 100, height: 300), withRowHeight: 100.0)
36 | XCTAssertEqual(firstRow, 0)
37 | }
38 |
39 | func testFirstRowWith1RowOffset() {
40 | let firstRow = GridCollectionViewLayout.firstRowInRect(CGRect(x: 0, y: 100, width: 100, height: 300), withRowHeight: 100.0)
41 | XCTAssertEqual(firstRow, 1)
42 | }
43 |
44 | func testFirstRowWithHalfRowOffset() {
45 | let firstRow = GridCollectionViewLayout.firstRowInRect(CGRect(x: 0, y: 50, width: 100, height: 300), withRowHeight: 100.0)
46 | XCTAssertEqual(firstRow, 0)
47 | }
48 |
49 | func testFirstRowWith2RowOffset() {
50 | let firstRow = GridCollectionViewLayout.firstRowInRect(CGRect(x: 0, y: 200, width: 100, height: 300), withRowHeight: 100.0)
51 | XCTAssertEqual(firstRow, 2)
52 | }
53 |
54 | func testFirstRowWithNegativeRectOffset() {
55 | let firstRow = GridCollectionViewLayout.firstRowInRect(CGRect(x: 0, y: -200, width: 100, height: 300), withRowHeight: 100.0)
56 | XCTAssertEqual(firstRow, 0)
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Example/ViewController.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Joakim Gyllström
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import UIKit
24 | import BSGridCollectionViewLayout
25 |
26 | class ViewController: UICollectionViewController {
27 | override func viewDidLoad() {
28 | super.viewDidLoad()
29 |
30 | collectionView?.backgroundColor = UIColor.white
31 |
32 | let layout = GridCollectionViewLayout()
33 | layout.itemsPerRow = 3
34 | layout.itemSpacing = 2
35 | layout.itemHeightRatio = 3/4
36 |
37 | collectionView?.collectionViewLayout = layout
38 |
39 | collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
40 | }
41 |
42 | // MARK: Data source
43 | override func numberOfSections(in collectionView: UICollectionView) -> Int {
44 | return 2
45 | }
46 |
47 | override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
48 | if section == 0 {
49 | return 11
50 | } else {
51 | return 18
52 | }
53 | }
54 |
55 | override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
56 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
57 | if (indexPath as NSIndexPath).section == 0 {
58 | cell.backgroundColor = UIColor.blue
59 | } else {
60 | cell.backgroundColor = UIColor.red
61 | }
62 |
63 | return cell
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/Example/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Tests/LastRowTests.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2016 Joakim Gyllström
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import XCTest
24 | @testable import BSGridCollectionViewLayout
25 |
26 | class LastRowTests: XCTestCase {
27 |
28 | func testLastRowInZeroRect() {
29 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect.zero, withRowHeight: 100, max: 3)
30 | XCTAssertEqual(lastRow, 0)
31 | }
32 |
33 | func testLastRowWithoutOffsetSmallMax() {
34 | let max = 2
35 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 0, width: 100, height: 300), withRowHeight: 100, max: max)
36 | XCTAssertEqual(lastRow, 1)
37 | }
38 |
39 | func testLastRowWithoutOffsetMediumMax() {
40 | let max = 3
41 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 0, width: 100, height: 300), withRowHeight: 100, max: max)
42 | XCTAssertEqual(lastRow, 2)
43 | }
44 |
45 | func testLastRowWithoutOffsetLargeMax() {
46 | let max = 8
47 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 0, width: 100, height: 300), withRowHeight: 100, max: max)
48 | XCTAssertEqual(lastRow, 2)
49 | }
50 |
51 | func testLastRowWith1RowOffsetSmallMax() {
52 | let max = 2
53 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 100, width: 100, height: 300), withRowHeight: 100, max: max)
54 | XCTAssertEqual(lastRow, 1)
55 | }
56 |
57 | func testLastRowWith1RowOffsetMediumMax() {
58 | let max = 3
59 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 100, width: 100, height: 300), withRowHeight: 100, max: max)
60 | XCTAssertEqual(lastRow, 2)
61 | }
62 |
63 | func testLastRowWith1RowOffsetLargeMax() {
64 | let max = 8
65 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 100, width: 100, height: 300), withRowHeight: 100, max: max)
66 | XCTAssertEqual(lastRow, 3)
67 | }
68 |
69 | func testLastRowWithHalfRowOffsetSmallMax() {
70 | let max = 2
71 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 50, width: 100, height: 300), withRowHeight: 100, max: max)
72 | XCTAssertEqual(lastRow, 1)
73 | }
74 |
75 | func testLastRowWithHalfRowOffsetMediumMax() {
76 | let max = 3
77 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 50, width: 100, height: 300), withRowHeight: 100, max: max)
78 | XCTAssertEqual(lastRow, 2)
79 | }
80 |
81 | func testLastRowWithHalfRowOffsetLargeMax() {
82 | let max = 8
83 | let lastRow = GridCollectionViewLayout.lastRowInRect(CGRect(x: 0, y: 50, width: 100, height: 300), withRowHeight: 100, max: max)
84 | XCTAssertEqual(lastRow, 3)
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/BSGridCollectionViewLayout.xcodeproj/xcshareddata/xcschemes/BSGridCollectionViewLayout.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 |
--------------------------------------------------------------------------------
/Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Sources/GridCollectionViewLayout.swift:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015 Joakim Gyllström
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | import UIKit
24 |
25 | /**
26 | Provides a grid collection view layout
27 | */
28 | public final class GridCollectionViewLayout: UICollectionViewLayout {
29 | /**
30 | Spacing between items (horizontal and vertical)
31 | */
32 | public var itemSpacing: CGFloat = 0 {
33 | didSet {
34 | itemSize = estimatedItemSize()
35 | }
36 | }
37 |
38 | /**
39 | Number of items per row
40 | */
41 | public var itemsPerRow = 3 {
42 | didSet {
43 | itemSize = estimatedItemSize()
44 | }
45 | }
46 |
47 | /**
48 | Item height ratio relative to it's width
49 | */
50 | public var itemHeightRatio: CGFloat = 1 {
51 | didSet {
52 | itemSize = estimatedItemSize()
53 | }
54 | }
55 |
56 | /**
57 | Size for each item
58 | */
59 | public private(set) var itemSize = CGSize.zero
60 |
61 | var items = 0
62 | var rows = 0
63 |
64 | public override func prepare() {
65 | // Set total number of items and rows
66 | items = estimatedNumberOfItems()
67 | rows = items / itemsPerRow + ((items % itemsPerRow > 0) ? 1 : 0)
68 |
69 | // Set item size
70 | itemSize = estimatedItemSize()
71 | }
72 |
73 | /**
74 | See UICollectionViewLayout documentation
75 | */
76 | public override var collectionViewContentSize: CGSize {
77 | guard let collectionView = collectionView, rows > 0 else {
78 | return CGSize.zero
79 | }
80 |
81 | let height = estimatedRowHeight() * CGFloat(rows)
82 | return CGSize(width: collectionView.bounds.width, height: height)
83 | }
84 |
85 | /**
86 | See UICollectionViewLayout documentation
87 | */
88 | public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
89 | return indexPathsInRect(rect).map { (indexPath) -> UICollectionViewLayoutAttributes? in
90 | return self.layoutAttributesForItem(at: indexPath)
91 | }.compactMap { $0 }
92 | }
93 |
94 | /**
95 | See UICollectionViewLayout documentation
96 | */
97 | public override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
98 | // Guard against negative row/sections.
99 | guard indexPath.row >= 0, indexPath.section >= 0 else {
100 | return nil
101 | }
102 |
103 | let itemIndex = flatIndex(indexPath) // index among total number of items
104 | let rowIndex = itemIndex % itemsPerRow // index within it's row
105 | let row = itemIndex / itemsPerRow // which row for that item
106 |
107 | let x = (CGFloat(rowIndex) * itemSpacing) + (CGFloat(rowIndex) * itemSize.width)
108 | let y = (CGFloat(row) * itemSpacing) + (CGFloat(row) * itemSize.height)
109 | let width = itemSize.width
110 | let height = itemSize.height
111 |
112 | let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
113 | attribute.frame = CGRect(x: x, y: y, width: width, height: height)
114 |
115 | return attribute
116 | }
117 |
118 | /**
119 | See UICollectionViewLayout documentation
120 | */
121 | public override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
122 | return true
123 | }
124 |
125 | // No decoration or supplementary views
126 | /**
127 | See UICollectionViewLayout documentation
128 | */
129 | public override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
130 | return nil
131 | }
132 | /**
133 | See UICollectionViewLayout documentation
134 | */
135 | public override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
136 | return nil
137 | }
138 | }
139 |
140 | extension GridCollectionViewLayout {
141 | /**
142 | Calculates which index paths are within a given rect
143 | - parameter rect: The rect which we want index paths for
144 | - returns: An array of indexPaths for that rect
145 | */
146 | func indexPathsInRect(_ rect: CGRect) -> [IndexPath] {
147 | // Make sure we have items/rows
148 | guard items > 0 && rows > 0 else { return [] }
149 |
150 | let rowHeight = estimatedRowHeight()
151 |
152 | let startRow = GridCollectionViewLayout.firstRowInRect(rect, withRowHeight: rowHeight)
153 | let endRow = GridCollectionViewLayout.lastRowInRect(rect, withRowHeight: rowHeight, max: rows)
154 | guard startRow <= endRow else { return [] }
155 |
156 | let startIndex = GridCollectionViewLayout.firstIndexInRow(min(startRow, endRow), withItemsPerRow: itemsPerRow)
157 | let endIndex = GridCollectionViewLayout.lastIndexInRow(max(startRow, endRow), withItemsPerRow: itemsPerRow, numberOfItems: items)
158 |
159 | guard startIndex <= endIndex else { return [] }
160 | let indexPaths = (startIndex...endIndex).map { indexPathFromFlatIndex($0) }
161 |
162 | return indexPaths
163 | }
164 |
165 | /**
166 | Calculates which row index would be first for a given rect.
167 | - parameter rect: The rect to check
168 | - parameter rowHeight: Height for a row
169 | - returns: First row index
170 | */
171 | static func firstRowInRect(_ rect: CGRect, withRowHeight rowHeight: CGFloat) -> Int {
172 | if rect.origin.y / rowHeight < 0 {
173 | return 0
174 | } else {
175 | return Int(rect.origin.y / rowHeight)
176 | }
177 | }
178 |
179 | /**
180 | Calculates which row index would be last for a given rect.
181 | - parameter rect: The rect to check
182 | - parameter rowHeight: Height for a row
183 | - returns: Last row index
184 | */
185 | static func lastRowInRect(_ rect: CGRect, withRowHeight rowHeight: CGFloat, max: Int) -> Int {
186 | guard rect.size.height >= rowHeight else { return 0 }
187 |
188 | if (rect.origin.y + rect.height) / rowHeight > CGFloat(max) {
189 | return max - 1
190 | } else {
191 | return Int(ceil((rect.origin.y + rect.height) / rowHeight)) - 1
192 | }
193 | }
194 |
195 | /**
196 | Calculates which index would be the first for a given row.
197 | - parameter row: Row index
198 | - parameter itemsPerRow: How many items there can be in a row
199 | - returns: First index
200 | */
201 | static func firstIndexInRow(_ row: Int, withItemsPerRow itemsPerRow: Int) -> Int {
202 | return row * itemsPerRow
203 | }
204 |
205 | /**
206 | Calculates which index would be the last for a given row.
207 | - parameter row: Row index
208 | - parameter itemsPerRow: How many items there can be in a row
209 | - parameter numberOfItems: The total number of items.
210 | - returns: Last index
211 | */
212 | static func lastIndexInRow(_ row: Int, withItemsPerRow itemsPerRow: Int, numberOfItems: Int) -> Int {
213 | let maxIndex = (row + 1) * itemsPerRow - 1
214 | let bounds = numberOfItems - 1
215 |
216 | if maxIndex > bounds {
217 | return bounds
218 | } else {
219 | return maxIndex
220 | }
221 | }
222 |
223 | /**
224 | Takes an index path (which are 2 dimensional) and turns it into a 1 dimensional index
225 | - parameter indexPath: The index path we want to flatten
226 | - returns: A flat index
227 | */
228 | func flatIndex(_ indexPath: IndexPath) -> Int {
229 | guard let collectionView = collectionView else {
230 | return 0
231 | }
232 |
233 | return (0..<(indexPath as NSIndexPath).section).reduce((indexPath as NSIndexPath).row) { $0 + collectionView.numberOfItems(inSection: $1)}
234 | }
235 |
236 | /**
237 | Converts a flat index into an index path
238 | - parameter index: The flat index
239 | - returns: An index path
240 | */
241 | func indexPathFromFlatIndex(_ index: Int) -> IndexPath {
242 | guard let collectionView = collectionView else {
243 | return IndexPath(item: 0, section: 0)
244 | }
245 |
246 | var item = index
247 | var section = 0
248 |
249 | while(item >= collectionView.numberOfItems(inSection: section)) {
250 | item -= collectionView.numberOfItems(inSection: section)
251 | section += 1
252 | }
253 |
254 | return IndexPath(item: item, section: section)
255 | }
256 |
257 | /**
258 | Estimated the size of the items
259 | - returns: Estimated item size
260 | */
261 | func estimatedItemSize() -> CGSize {
262 | guard let collectionView = collectionView else {
263 | return CGSize.zero
264 | }
265 |
266 | let itemWidth = (collectionView.bounds.width - CGFloat(itemsPerRow - 1) * itemSpacing) / CGFloat(itemsPerRow)
267 | return CGSize(width: itemWidth, height: itemWidth * itemHeightRatio)
268 | }
269 |
270 | /**
271 | Estimated total number of items
272 | - returns: Total number of items
273 | */
274 | func estimatedNumberOfItems() -> Int {
275 | guard let collectionView = collectionView else {
276 | return 0
277 | }
278 |
279 | return (0.. CGFloat {
287 | return itemSize.height+itemSpacing
288 | }
289 | }
290 |
--------------------------------------------------------------------------------
/BSGridCollectionViewLayout.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 552D02E021D4E9E10017BF81 /* BSGridCollectionViewLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 552D02DE21D4E9E10017BF81 /* BSGridCollectionViewLayout.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 558BE65621D4EB4E00F06E8B /* GridCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558BE65521D4EB4E00F06E8B /* GridCollectionViewLayout.swift */; };
12 | 558BE65E21D4EBB800F06E8B /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558BE65D21D4EBB800F06E8B /* Tests.swift */; };
13 | 558BE66021D4EBB800F06E8B /* BSGridCollectionViewLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 552D02DB21D4E9E10017BF81 /* BSGridCollectionViewLayout.framework */; };
14 | 558BE66A21D4EBED00F06E8B /* LastIndexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558BE66621D4EBED00F06E8B /* LastIndexTests.swift */; };
15 | 558BE66B21D4EBED00F06E8B /* LastRowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558BE66721D4EBED00F06E8B /* LastRowTests.swift */; };
16 | 558BE66C21D4EBED00F06E8B /* FirstRowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558BE66821D4EBED00F06E8B /* FirstRowTests.swift */; };
17 | 558BE66D21D4EBED00F06E8B /* FirstIndexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558BE66921D4EBED00F06E8B /* FirstIndexTests.swift */; };
18 | 558BE67521D4EC3B00F06E8B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558BE67421D4EC3B00F06E8B /* AppDelegate.swift */; };
19 | 558BE67721D4EC3B00F06E8B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558BE67621D4EC3B00F06E8B /* ViewController.swift */; };
20 | 558BE67A21D4EC3B00F06E8B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 558BE67821D4EC3B00F06E8B /* Main.storyboard */; };
21 | 558BE67C21D4EC3B00F06E8B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 558BE67B21D4EC3B00F06E8B /* Assets.xcassets */; };
22 | 5595158A21D4ED8A007E31CE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5595158921D4ED8A007E31CE /* LaunchScreen.storyboard */; };
23 | 55CB6AF621D4ECD40014DB72 /* BSGridCollectionViewLayout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 552D02DB21D4E9E10017BF81 /* BSGridCollectionViewLayout.framework */; };
24 | 55D03E652253CDFD00567C18 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 55D03E642253CDFD00567C18 /* Default-568h@2x.png */; };
25 | /* End PBXBuildFile section */
26 |
27 | /* Begin PBXContainerItemProxy section */
28 | 558BE66121D4EBB800F06E8B /* PBXContainerItemProxy */ = {
29 | isa = PBXContainerItemProxy;
30 | containerPortal = 552D02D221D4E9E10017BF81 /* Project object */;
31 | proxyType = 1;
32 | remoteGlobalIDString = 552D02DA21D4E9E10017BF81;
33 | remoteInfo = BSGridCollectionViewLayout;
34 | };
35 | /* End PBXContainerItemProxy section */
36 |
37 | /* Begin PBXFileReference section */
38 | 552D02DB21D4E9E10017BF81 /* BSGridCollectionViewLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BSGridCollectionViewLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 552D02DE21D4E9E10017BF81 /* BSGridCollectionViewLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BSGridCollectionViewLayout.h; sourceTree = ""; };
40 | 552D02DF21D4E9E10017BF81 /* InfoSource.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = InfoSource.plist; sourceTree = ""; };
41 | 558BE65521D4EB4E00F06E8B /* GridCollectionViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GridCollectionViewLayout.swift; sourceTree = ""; };
42 | 558BE65B21D4EBB800F06E8B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
43 | 558BE65D21D4EBB800F06E8B /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; };
44 | 558BE66621D4EBED00F06E8B /* LastIndexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LastIndexTests.swift; sourceTree = ""; };
45 | 558BE66721D4EBED00F06E8B /* LastRowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LastRowTests.swift; sourceTree = ""; };
46 | 558BE66821D4EBED00F06E8B /* FirstRowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstRowTests.swift; sourceTree = ""; };
47 | 558BE66921D4EBED00F06E8B /* FirstIndexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstIndexTests.swift; sourceTree = ""; };
48 | 558BE67221D4EC3B00F06E8B /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
49 | 558BE67421D4EC3B00F06E8B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
50 | 558BE67621D4EC3B00F06E8B /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
51 | 558BE67921D4EC3B00F06E8B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
52 | 558BE67B21D4EC3B00F06E8B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
53 | 558BE68021D4EC3B00F06E8B /* InfoExample.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = InfoExample.plist; sourceTree = ""; };
54 | 5595158921D4ED8A007E31CE /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
55 | 5595158B21D4EE09007E31CE /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
56 | 5595158C21D4EE14007E31CE /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
57 | 5595158D21D4EE1E007E31CE /* BSGridCollectionViewLayout.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = BSGridCollectionViewLayout.podspec; sourceTree = ""; };
58 | 55D03E642253CDFD00567C18 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; };
59 | /* End PBXFileReference section */
60 |
61 | /* Begin PBXFrameworksBuildPhase section */
62 | 552D02D821D4E9E10017BF81 /* Frameworks */ = {
63 | isa = PBXFrameworksBuildPhase;
64 | buildActionMask = 2147483647;
65 | files = (
66 | );
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | 558BE65821D4EBB800F06E8B /* Frameworks */ = {
70 | isa = PBXFrameworksBuildPhase;
71 | buildActionMask = 2147483647;
72 | files = (
73 | 558BE66021D4EBB800F06E8B /* BSGridCollectionViewLayout.framework in Frameworks */,
74 | );
75 | runOnlyForDeploymentPostprocessing = 0;
76 | };
77 | 558BE66F21D4EC3B00F06E8B /* Frameworks */ = {
78 | isa = PBXFrameworksBuildPhase;
79 | buildActionMask = 2147483647;
80 | files = (
81 | 55CB6AF621D4ECD40014DB72 /* BSGridCollectionViewLayout.framework in Frameworks */,
82 | );
83 | runOnlyForDeploymentPostprocessing = 0;
84 | };
85 | /* End PBXFrameworksBuildPhase section */
86 |
87 | /* Begin PBXGroup section */
88 | 552D02D121D4E9E10017BF81 = {
89 | isa = PBXGroup;
90 | children = (
91 | 55D03E642253CDFD00567C18 /* Default-568h@2x.png */,
92 | 5595158B21D4EE09007E31CE /* README.md */,
93 | 5595158C21D4EE14007E31CE /* LICENSE */,
94 | 5595158D21D4EE1E007E31CE /* BSGridCollectionViewLayout.podspec */,
95 | 552D02DD21D4E9E10017BF81 /* Sources */,
96 | 558BE65C21D4EBB800F06E8B /* Tests */,
97 | 558BE67321D4EC3B00F06E8B /* Example */,
98 | 552D02DC21D4E9E10017BF81 /* Products */,
99 | 55CB6AF521D4ECD40014DB72 /* Frameworks */,
100 | );
101 | sourceTree = "";
102 | };
103 | 552D02DC21D4E9E10017BF81 /* Products */ = {
104 | isa = PBXGroup;
105 | children = (
106 | 552D02DB21D4E9E10017BF81 /* BSGridCollectionViewLayout.framework */,
107 | 558BE65B21D4EBB800F06E8B /* Tests.xctest */,
108 | 558BE67221D4EC3B00F06E8B /* Example.app */,
109 | );
110 | name = Products;
111 | sourceTree = "";
112 | };
113 | 552D02DD21D4E9E10017BF81 /* Sources */ = {
114 | isa = PBXGroup;
115 | children = (
116 | 558BE65521D4EB4E00F06E8B /* GridCollectionViewLayout.swift */,
117 | 552D02DE21D4E9E10017BF81 /* BSGridCollectionViewLayout.h */,
118 | 552D02DF21D4E9E10017BF81 /* InfoSource.plist */,
119 | );
120 | path = Sources;
121 | sourceTree = "";
122 | };
123 | 558BE65C21D4EBB800F06E8B /* Tests */ = {
124 | isa = PBXGroup;
125 | children = (
126 | 558BE66921D4EBED00F06E8B /* FirstIndexTests.swift */,
127 | 558BE66821D4EBED00F06E8B /* FirstRowTests.swift */,
128 | 558BE66621D4EBED00F06E8B /* LastIndexTests.swift */,
129 | 558BE66721D4EBED00F06E8B /* LastRowTests.swift */,
130 | 558BE65D21D4EBB800F06E8B /* Tests.swift */,
131 | );
132 | path = Tests;
133 | sourceTree = "";
134 | };
135 | 558BE67321D4EC3B00F06E8B /* Example */ = {
136 | isa = PBXGroup;
137 | children = (
138 | 558BE67421D4EC3B00F06E8B /* AppDelegate.swift */,
139 | 558BE67621D4EC3B00F06E8B /* ViewController.swift */,
140 | 558BE67821D4EC3B00F06E8B /* Main.storyboard */,
141 | 558BE67B21D4EC3B00F06E8B /* Assets.xcassets */,
142 | 558BE68021D4EC3B00F06E8B /* InfoExample.plist */,
143 | 5595158921D4ED8A007E31CE /* LaunchScreen.storyboard */,
144 | );
145 | path = Example;
146 | sourceTree = "";
147 | };
148 | 55CB6AF521D4ECD40014DB72 /* Frameworks */ = {
149 | isa = PBXGroup;
150 | children = (
151 | );
152 | name = Frameworks;
153 | sourceTree = "";
154 | };
155 | /* End PBXGroup section */
156 |
157 | /* Begin PBXHeadersBuildPhase section */
158 | 552D02D621D4E9E10017BF81 /* Headers */ = {
159 | isa = PBXHeadersBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 552D02E021D4E9E10017BF81 /* BSGridCollectionViewLayout.h in Headers */,
163 | );
164 | runOnlyForDeploymentPostprocessing = 0;
165 | };
166 | /* End PBXHeadersBuildPhase section */
167 |
168 | /* Begin PBXNativeTarget section */
169 | 552D02DA21D4E9E10017BF81 /* BSGridCollectionViewLayout */ = {
170 | isa = PBXNativeTarget;
171 | buildConfigurationList = 552D02E321D4E9E10017BF81 /* Build configuration list for PBXNativeTarget "BSGridCollectionViewLayout" */;
172 | buildPhases = (
173 | 552D02D621D4E9E10017BF81 /* Headers */,
174 | 552D02D721D4E9E10017BF81 /* Sources */,
175 | 552D02D821D4E9E10017BF81 /* Frameworks */,
176 | 552D02D921D4E9E10017BF81 /* Resources */,
177 | );
178 | buildRules = (
179 | );
180 | dependencies = (
181 | );
182 | name = BSGridCollectionViewLayout;
183 | productName = BSGridCollectionViewLayout;
184 | productReference = 552D02DB21D4E9E10017BF81 /* BSGridCollectionViewLayout.framework */;
185 | productType = "com.apple.product-type.framework";
186 | };
187 | 558BE65A21D4EBB800F06E8B /* Tests */ = {
188 | isa = PBXNativeTarget;
189 | buildConfigurationList = 558BE66321D4EBB800F06E8B /* Build configuration list for PBXNativeTarget "Tests" */;
190 | buildPhases = (
191 | 558BE65721D4EBB800F06E8B /* Sources */,
192 | 558BE65821D4EBB800F06E8B /* Frameworks */,
193 | 558BE65921D4EBB800F06E8B /* Resources */,
194 | );
195 | buildRules = (
196 | );
197 | dependencies = (
198 | 558BE66221D4EBB800F06E8B /* PBXTargetDependency */,
199 | );
200 | name = Tests;
201 | productName = Tests;
202 | productReference = 558BE65B21D4EBB800F06E8B /* Tests.xctest */;
203 | productType = "com.apple.product-type.bundle.unit-test";
204 | };
205 | 558BE67121D4EC3B00F06E8B /* Example */ = {
206 | isa = PBXNativeTarget;
207 | buildConfigurationList = 558BE68121D4EC3B00F06E8B /* Build configuration list for PBXNativeTarget "Example" */;
208 | buildPhases = (
209 | 558BE66E21D4EC3B00F06E8B /* Sources */,
210 | 558BE66F21D4EC3B00F06E8B /* Frameworks */,
211 | 558BE67021D4EC3B00F06E8B /* Resources */,
212 | );
213 | buildRules = (
214 | );
215 | dependencies = (
216 | );
217 | name = Example;
218 | productName = Example;
219 | productReference = 558BE67221D4EC3B00F06E8B /* Example.app */;
220 | productType = "com.apple.product-type.application";
221 | };
222 | /* End PBXNativeTarget section */
223 |
224 | /* Begin PBXProject section */
225 | 552D02D221D4E9E10017BF81 /* Project object */ = {
226 | isa = PBXProject;
227 | attributes = {
228 | LastSwiftUpdateCheck = 1010;
229 | LastUpgradeCheck = 1010;
230 | ORGANIZATIONNAME = "Joakim Gyllström";
231 | TargetAttributes = {
232 | 552D02DA21D4E9E10017BF81 = {
233 | CreatedOnToolsVersion = 10.1;
234 | LastSwiftMigration = 1020;
235 | };
236 | 558BE65A21D4EBB800F06E8B = {
237 | CreatedOnToolsVersion = 10.1;
238 | LastSwiftMigration = 1020;
239 | };
240 | 558BE67121D4EC3B00F06E8B = {
241 | CreatedOnToolsVersion = 10.1;
242 | LastSwiftMigration = 1020;
243 | };
244 | };
245 | };
246 | buildConfigurationList = 552D02D521D4E9E10017BF81 /* Build configuration list for PBXProject "BSGridCollectionViewLayout" */;
247 | compatibilityVersion = "Xcode 9.3";
248 | developmentRegion = en;
249 | hasScannedForEncodings = 0;
250 | knownRegions = (
251 | en,
252 | Base,
253 | );
254 | mainGroup = 552D02D121D4E9E10017BF81;
255 | productRefGroup = 552D02DC21D4E9E10017BF81 /* Products */;
256 | projectDirPath = "";
257 | projectRoot = "";
258 | targets = (
259 | 552D02DA21D4E9E10017BF81 /* BSGridCollectionViewLayout */,
260 | 558BE65A21D4EBB800F06E8B /* Tests */,
261 | 558BE67121D4EC3B00F06E8B /* Example */,
262 | );
263 | };
264 | /* End PBXProject section */
265 |
266 | /* Begin PBXResourcesBuildPhase section */
267 | 552D02D921D4E9E10017BF81 /* Resources */ = {
268 | isa = PBXResourcesBuildPhase;
269 | buildActionMask = 2147483647;
270 | files = (
271 | );
272 | runOnlyForDeploymentPostprocessing = 0;
273 | };
274 | 558BE65921D4EBB800F06E8B /* Resources */ = {
275 | isa = PBXResourcesBuildPhase;
276 | buildActionMask = 2147483647;
277 | files = (
278 | );
279 | runOnlyForDeploymentPostprocessing = 0;
280 | };
281 | 558BE67021D4EC3B00F06E8B /* Resources */ = {
282 | isa = PBXResourcesBuildPhase;
283 | buildActionMask = 2147483647;
284 | files = (
285 | 5595158A21D4ED8A007E31CE /* LaunchScreen.storyboard in Resources */,
286 | 55D03E652253CDFD00567C18 /* Default-568h@2x.png in Resources */,
287 | 558BE67C21D4EC3B00F06E8B /* Assets.xcassets in Resources */,
288 | 558BE67A21D4EC3B00F06E8B /* Main.storyboard in Resources */,
289 | );
290 | runOnlyForDeploymentPostprocessing = 0;
291 | };
292 | /* End PBXResourcesBuildPhase section */
293 |
294 | /* Begin PBXSourcesBuildPhase section */
295 | 552D02D721D4E9E10017BF81 /* Sources */ = {
296 | isa = PBXSourcesBuildPhase;
297 | buildActionMask = 2147483647;
298 | files = (
299 | 558BE65621D4EB4E00F06E8B /* GridCollectionViewLayout.swift in Sources */,
300 | );
301 | runOnlyForDeploymentPostprocessing = 0;
302 | };
303 | 558BE65721D4EBB800F06E8B /* Sources */ = {
304 | isa = PBXSourcesBuildPhase;
305 | buildActionMask = 2147483647;
306 | files = (
307 | 558BE66D21D4EBED00F06E8B /* FirstIndexTests.swift in Sources */,
308 | 558BE66A21D4EBED00F06E8B /* LastIndexTests.swift in Sources */,
309 | 558BE66C21D4EBED00F06E8B /* FirstRowTests.swift in Sources */,
310 | 558BE66B21D4EBED00F06E8B /* LastRowTests.swift in Sources */,
311 | 558BE65E21D4EBB800F06E8B /* Tests.swift in Sources */,
312 | );
313 | runOnlyForDeploymentPostprocessing = 0;
314 | };
315 | 558BE66E21D4EC3B00F06E8B /* Sources */ = {
316 | isa = PBXSourcesBuildPhase;
317 | buildActionMask = 2147483647;
318 | files = (
319 | 558BE67721D4EC3B00F06E8B /* ViewController.swift in Sources */,
320 | 558BE67521D4EC3B00F06E8B /* AppDelegate.swift in Sources */,
321 | );
322 | runOnlyForDeploymentPostprocessing = 0;
323 | };
324 | /* End PBXSourcesBuildPhase section */
325 |
326 | /* Begin PBXTargetDependency section */
327 | 558BE66221D4EBB800F06E8B /* PBXTargetDependency */ = {
328 | isa = PBXTargetDependency;
329 | target = 552D02DA21D4E9E10017BF81 /* BSGridCollectionViewLayout */;
330 | targetProxy = 558BE66121D4EBB800F06E8B /* PBXContainerItemProxy */;
331 | };
332 | /* End PBXTargetDependency section */
333 |
334 | /* Begin PBXVariantGroup section */
335 | 558BE67821D4EC3B00F06E8B /* Main.storyboard */ = {
336 | isa = PBXVariantGroup;
337 | children = (
338 | 558BE67921D4EC3B00F06E8B /* Base */,
339 | );
340 | name = Main.storyboard;
341 | sourceTree = "";
342 | };
343 | /* End PBXVariantGroup section */
344 |
345 | /* Begin XCBuildConfiguration section */
346 | 552D02E121D4E9E10017BF81 /* Debug */ = {
347 | isa = XCBuildConfiguration;
348 | buildSettings = {
349 | ALWAYS_SEARCH_USER_PATHS = NO;
350 | CLANG_ANALYZER_NONNULL = YES;
351 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
352 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
353 | CLANG_CXX_LIBRARY = "libc++";
354 | CLANG_ENABLE_MODULES = YES;
355 | CLANG_ENABLE_OBJC_ARC = YES;
356 | CLANG_ENABLE_OBJC_WEAK = YES;
357 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
358 | CLANG_WARN_BOOL_CONVERSION = YES;
359 | CLANG_WARN_COMMA = YES;
360 | CLANG_WARN_CONSTANT_CONVERSION = YES;
361 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
362 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
363 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
364 | CLANG_WARN_EMPTY_BODY = YES;
365 | CLANG_WARN_ENUM_CONVERSION = YES;
366 | CLANG_WARN_INFINITE_RECURSION = YES;
367 | CLANG_WARN_INT_CONVERSION = YES;
368 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
369 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
370 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
371 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
372 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
373 | CLANG_WARN_STRICT_PROTOTYPES = YES;
374 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
375 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
376 | CLANG_WARN_UNREACHABLE_CODE = YES;
377 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
378 | CODE_SIGN_IDENTITY = "iPhone Developer";
379 | COPY_PHASE_STRIP = NO;
380 | CURRENT_PROJECT_VERSION = 1;
381 | DEBUG_INFORMATION_FORMAT = dwarf;
382 | ENABLE_STRICT_OBJC_MSGSEND = YES;
383 | ENABLE_TESTABILITY = YES;
384 | GCC_C_LANGUAGE_STANDARD = gnu11;
385 | GCC_DYNAMIC_NO_PIC = NO;
386 | GCC_NO_COMMON_BLOCKS = YES;
387 | GCC_OPTIMIZATION_LEVEL = 0;
388 | GCC_PREPROCESSOR_DEFINITIONS = (
389 | "DEBUG=1",
390 | "$(inherited)",
391 | );
392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
394 | GCC_WARN_UNDECLARED_SELECTOR = YES;
395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
396 | GCC_WARN_UNUSED_FUNCTION = YES;
397 | GCC_WARN_UNUSED_VARIABLE = YES;
398 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
399 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
400 | MTL_FAST_MATH = YES;
401 | ONLY_ACTIVE_ARCH = YES;
402 | SDKROOT = iphoneos;
403 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
404 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
405 | VERSIONING_SYSTEM = "apple-generic";
406 | VERSION_INFO_PREFIX = "";
407 | };
408 | name = Debug;
409 | };
410 | 552D02E221D4E9E10017BF81 /* Release */ = {
411 | isa = XCBuildConfiguration;
412 | buildSettings = {
413 | ALWAYS_SEARCH_USER_PATHS = NO;
414 | CLANG_ANALYZER_NONNULL = YES;
415 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
416 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
417 | CLANG_CXX_LIBRARY = "libc++";
418 | CLANG_ENABLE_MODULES = YES;
419 | CLANG_ENABLE_OBJC_ARC = YES;
420 | CLANG_ENABLE_OBJC_WEAK = YES;
421 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
422 | CLANG_WARN_BOOL_CONVERSION = YES;
423 | CLANG_WARN_COMMA = YES;
424 | CLANG_WARN_CONSTANT_CONVERSION = YES;
425 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
426 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
427 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
428 | CLANG_WARN_EMPTY_BODY = YES;
429 | CLANG_WARN_ENUM_CONVERSION = YES;
430 | CLANG_WARN_INFINITE_RECURSION = YES;
431 | CLANG_WARN_INT_CONVERSION = YES;
432 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
433 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
434 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
435 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
436 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
437 | CLANG_WARN_STRICT_PROTOTYPES = YES;
438 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
439 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
440 | CLANG_WARN_UNREACHABLE_CODE = YES;
441 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
442 | CODE_SIGN_IDENTITY = "iPhone Developer";
443 | COPY_PHASE_STRIP = NO;
444 | CURRENT_PROJECT_VERSION = 1;
445 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
446 | ENABLE_NS_ASSERTIONS = NO;
447 | ENABLE_STRICT_OBJC_MSGSEND = YES;
448 | GCC_C_LANGUAGE_STANDARD = gnu11;
449 | GCC_NO_COMMON_BLOCKS = YES;
450 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
451 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
452 | GCC_WARN_UNDECLARED_SELECTOR = YES;
453 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
454 | GCC_WARN_UNUSED_FUNCTION = YES;
455 | GCC_WARN_UNUSED_VARIABLE = YES;
456 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
457 | MTL_ENABLE_DEBUG_INFO = NO;
458 | MTL_FAST_MATH = YES;
459 | SDKROOT = iphoneos;
460 | SWIFT_COMPILATION_MODE = wholemodule;
461 | SWIFT_OPTIMIZATION_LEVEL = "-O";
462 | VALIDATE_PRODUCT = YES;
463 | VERSIONING_SYSTEM = "apple-generic";
464 | VERSION_INFO_PREFIX = "";
465 | };
466 | name = Release;
467 | };
468 | 552D02E421D4E9E10017BF81 /* Debug */ = {
469 | isa = XCBuildConfiguration;
470 | buildSettings = {
471 | CLANG_ENABLE_MODULES = YES;
472 | CODE_SIGN_IDENTITY = "";
473 | CODE_SIGN_STYLE = Automatic;
474 | DEFINES_MODULE = YES;
475 | DEVELOPMENT_TEAM = Y2NHS7RD78;
476 | DYLIB_COMPATIBILITY_VERSION = 1;
477 | DYLIB_CURRENT_VERSION = 1;
478 | DYLIB_INSTALL_NAME_BASE = "@rpath";
479 | INFOPLIST_FILE = "$(SRCROOT)/Sources/InfoSource.plist";
480 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
481 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
482 | LD_RUNPATH_SEARCH_PATHS = (
483 | "$(inherited)",
484 | "@executable_path/Frameworks",
485 | "@loader_path/Frameworks",
486 | );
487 | PRODUCT_BUNDLE_IDENTIFIER = se.backslashed.BSGridCollectionViewLayout;
488 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
489 | SKIP_INSTALL = YES;
490 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
491 | SWIFT_VERSION = 5.0;
492 | TARGETED_DEVICE_FAMILY = "1,2";
493 | };
494 | name = Debug;
495 | };
496 | 552D02E521D4E9E10017BF81 /* Release */ = {
497 | isa = XCBuildConfiguration;
498 | buildSettings = {
499 | CLANG_ENABLE_MODULES = YES;
500 | CODE_SIGN_IDENTITY = "";
501 | CODE_SIGN_STYLE = Automatic;
502 | DEFINES_MODULE = YES;
503 | DEVELOPMENT_TEAM = Y2NHS7RD78;
504 | DYLIB_COMPATIBILITY_VERSION = 1;
505 | DYLIB_CURRENT_VERSION = 1;
506 | DYLIB_INSTALL_NAME_BASE = "@rpath";
507 | INFOPLIST_FILE = "$(SRCROOT)/Sources/InfoSource.plist";
508 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
509 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
510 | LD_RUNPATH_SEARCH_PATHS = (
511 | "$(inherited)",
512 | "@executable_path/Frameworks",
513 | "@loader_path/Frameworks",
514 | );
515 | PRODUCT_BUNDLE_IDENTIFIER = se.backslashed.BSGridCollectionViewLayout;
516 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
517 | SKIP_INSTALL = YES;
518 | SWIFT_VERSION = 5.0;
519 | TARGETED_DEVICE_FAMILY = "1,2";
520 | };
521 | name = Release;
522 | };
523 | 558BE66421D4EBB800F06E8B /* Debug */ = {
524 | isa = XCBuildConfiguration;
525 | buildSettings = {
526 | CODE_SIGN_STYLE = Automatic;
527 | DEVELOPMENT_TEAM = Y2NHS7RD78;
528 | LD_RUNPATH_SEARCH_PATHS = (
529 | "$(inherited)",
530 | "@executable_path/Frameworks",
531 | "@loader_path/Frameworks",
532 | );
533 | PRODUCT_BUNDLE_IDENTIFIER = se.backslashed.Tests;
534 | PRODUCT_NAME = "$(TARGET_NAME)";
535 | SWIFT_VERSION = 5.0;
536 | TARGETED_DEVICE_FAMILY = "1,2";
537 | };
538 | name = Debug;
539 | };
540 | 558BE66521D4EBB800F06E8B /* Release */ = {
541 | isa = XCBuildConfiguration;
542 | buildSettings = {
543 | CODE_SIGN_STYLE = Automatic;
544 | DEVELOPMENT_TEAM = Y2NHS7RD78;
545 | LD_RUNPATH_SEARCH_PATHS = (
546 | "$(inherited)",
547 | "@executable_path/Frameworks",
548 | "@loader_path/Frameworks",
549 | );
550 | PRODUCT_BUNDLE_IDENTIFIER = se.backslashed.Tests;
551 | PRODUCT_NAME = "$(TARGET_NAME)";
552 | SWIFT_VERSION = 5.0;
553 | TARGETED_DEVICE_FAMILY = "1,2";
554 | };
555 | name = Release;
556 | };
557 | 558BE68221D4EC3B00F06E8B /* Debug */ = {
558 | isa = XCBuildConfiguration;
559 | buildSettings = {
560 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
561 | CODE_SIGN_STYLE = Automatic;
562 | DEVELOPMENT_TEAM = Y2NHS7RD78;
563 | INFOPLIST_FILE = "$(SRCROOT)/Example/InfoExample.plist";
564 | LD_RUNPATH_SEARCH_PATHS = (
565 | "$(inherited)",
566 | "@executable_path/Frameworks",
567 | );
568 | PRODUCT_BUNDLE_IDENTIFIER = se.backslashed.Example;
569 | PRODUCT_NAME = "$(TARGET_NAME)";
570 | SWIFT_VERSION = 5.0;
571 | TARGETED_DEVICE_FAMILY = "1,2";
572 | };
573 | name = Debug;
574 | };
575 | 558BE68321D4EC3B00F06E8B /* Release */ = {
576 | isa = XCBuildConfiguration;
577 | buildSettings = {
578 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
579 | CODE_SIGN_STYLE = Automatic;
580 | DEVELOPMENT_TEAM = Y2NHS7RD78;
581 | INFOPLIST_FILE = "$(SRCROOT)/Example/InfoExample.plist";
582 | LD_RUNPATH_SEARCH_PATHS = (
583 | "$(inherited)",
584 | "@executable_path/Frameworks",
585 | );
586 | PRODUCT_BUNDLE_IDENTIFIER = se.backslashed.Example;
587 | PRODUCT_NAME = "$(TARGET_NAME)";
588 | SWIFT_VERSION = 5.0;
589 | TARGETED_DEVICE_FAMILY = "1,2";
590 | };
591 | name = Release;
592 | };
593 | /* End XCBuildConfiguration section */
594 |
595 | /* Begin XCConfigurationList section */
596 | 552D02D521D4E9E10017BF81 /* Build configuration list for PBXProject "BSGridCollectionViewLayout" */ = {
597 | isa = XCConfigurationList;
598 | buildConfigurations = (
599 | 552D02E121D4E9E10017BF81 /* Debug */,
600 | 552D02E221D4E9E10017BF81 /* Release */,
601 | );
602 | defaultConfigurationIsVisible = 0;
603 | defaultConfigurationName = Release;
604 | };
605 | 552D02E321D4E9E10017BF81 /* Build configuration list for PBXNativeTarget "BSGridCollectionViewLayout" */ = {
606 | isa = XCConfigurationList;
607 | buildConfigurations = (
608 | 552D02E421D4E9E10017BF81 /* Debug */,
609 | 552D02E521D4E9E10017BF81 /* Release */,
610 | );
611 | defaultConfigurationIsVisible = 0;
612 | defaultConfigurationName = Release;
613 | };
614 | 558BE66321D4EBB800F06E8B /* Build configuration list for PBXNativeTarget "Tests" */ = {
615 | isa = XCConfigurationList;
616 | buildConfigurations = (
617 | 558BE66421D4EBB800F06E8B /* Debug */,
618 | 558BE66521D4EBB800F06E8B /* Release */,
619 | );
620 | defaultConfigurationIsVisible = 0;
621 | defaultConfigurationName = Release;
622 | };
623 | 558BE68121D4EC3B00F06E8B /* Build configuration list for PBXNativeTarget "Example" */ = {
624 | isa = XCConfigurationList;
625 | buildConfigurations = (
626 | 558BE68221D4EC3B00F06E8B /* Debug */,
627 | 558BE68321D4EC3B00F06E8B /* Release */,
628 | );
629 | defaultConfigurationIsVisible = 0;
630 | defaultConfigurationName = Release;
631 | };
632 | /* End XCConfigurationList section */
633 | };
634 | rootObject = 552D02D221D4E9E10017BF81 /* Project object */;
635 | }
636 |
--------------------------------------------------------------------------------