├── Circular.png
├── Vertical.png
├── Horizontal.png
├── VerticalSelected.png
├── CentralizedVertical.png
├── CentralizedHorizontal.png
├── VPCollectionViewLayoutExample
├── VPCollectionViewLayoutExample
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── sample-1.imageset
│ │ │ ├── sample-1.jpeg
│ │ │ └── Contents.json
│ │ ├── sample-10.imageset
│ │ │ ├── sample-10.jpg
│ │ │ └── Contents.json
│ │ ├── sample-2.imageset
│ │ │ ├── sample-2.jpg
│ │ │ └── Contents.json
│ │ ├── sample-3.imageset
│ │ │ ├── sample-3.jpg
│ │ │ └── Contents.json
│ │ ├── sample-4.imageset
│ │ │ ├── sample-4.jpg
│ │ │ └── Contents.json
│ │ ├── sample-5.imageset
│ │ │ ├── sample-5.jpg
│ │ │ └── Contents.json
│ │ ├── sample-6.imageset
│ │ │ ├── sample-6.jpg
│ │ │ └── Contents.json
│ │ ├── sample-7.imageset
│ │ │ ├── sample-7.jpg
│ │ │ └── Contents.json
│ │ ├── sample-8.imageset
│ │ │ ├── sample-8.jpg
│ │ │ └── Contents.json
│ │ ├── sample-9.imageset
│ │ │ ├── sample-9.jpg
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── SampleCollectionViewCell.swift
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── AppDelegate.swift
│ ├── ViewController.swift
│ └── SampleCollectionViewCell.xib
├── VPCollectionViewLayoutExampleTests
│ ├── Info.plist
│ └── VPCollectionViewLayoutExampleTests.swift
├── VPCollectionViewLayoutExampleUITests
│ ├── Info.plist
│ └── VPCollectionViewLayoutExampleUITests.swift
└── VPCollectionViewLayoutExample.xcodeproj
│ └── project.pbxproj
├── LICENSE
├── .gitignore
├── README.md
└── VPCollectionViewLayout
└── VPCollectionViewLayout.swift
/Circular.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/Circular.png
--------------------------------------------------------------------------------
/Vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/Vertical.png
--------------------------------------------------------------------------------
/Horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/Horizontal.png
--------------------------------------------------------------------------------
/VerticalSelected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VerticalSelected.png
--------------------------------------------------------------------------------
/CentralizedVertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/CentralizedVertical.png
--------------------------------------------------------------------------------
/CentralizedHorizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/CentralizedHorizontal.png
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-1.imageset/sample-1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-1.imageset/sample-1.jpeg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-10.imageset/sample-10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-10.imageset/sample-10.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-2.imageset/sample-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-2.imageset/sample-2.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-3.imageset/sample-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-3.imageset/sample-3.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-4.imageset/sample-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-4.imageset/sample-4.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-5.imageset/sample-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-5.imageset/sample-5.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-6.imageset/sample-6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-6.imageset/sample-6.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-7.imageset/sample-7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-7.imageset/sample-7.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-8.imageset/sample-8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-8.imageset/sample-8.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-9.imageset/sample-9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/varunpm1/VPCollectionViewLayout/HEAD/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-9.imageset/sample-9.jpg
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-2.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-3.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-4.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-5.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-6.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-7.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-8.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-8.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-9.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-9.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-1.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Assets.xcassets/sample-10.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "sample-10.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/SampleCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SampleCollectionViewCell.swift
3 | // VPCollectionViewLayoutExample
4 | //
5 | // Created by Varun P M on 05/11/17.
6 | // Copyright © 2017 Varun P M. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SampleCollectionViewCell: UICollectionViewCell {
12 | @IBOutlet weak var cellTitleLabel: UILabel!
13 | @IBOutlet weak var cellImageView: UIImageView!
14 |
15 | override func awakeFromNib() {
16 | super.awakeFromNib()
17 | // Initialization code
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExampleUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Varun P 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 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExampleTests/VPCollectionViewLayoutExampleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VPCollectionViewLayoutExampleTests.swift
3 | // VPCollectionViewLayoutExampleTests
4 | //
5 | // Created by Varun P M on 05/11/17.
6 | // Copyright © 2017 Varun P M. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import VPCollectionViewLayoutExample
11 |
12 | class VPCollectionViewLayoutExampleTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExampleUITests/VPCollectionViewLayoutExampleUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VPCollectionViewLayoutExampleUITests.swift
3 | // VPCollectionViewLayoutExampleUITests
4 | //
5 | // Created by Varun P M on 05/11/17.
6 | // Copyright © 2017 Varun P M. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class VPCollectionViewLayoutExampleUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 |
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 |
18 | // In UI tests it is usually best to stop immediately when a failure occurs.
19 | continueAfterFailure = false
20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
21 | XCUIApplication().launch()
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | override func tearDown() {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | super.tearDown()
29 | }
30 |
31 | func testExample() {
32 | // Use recording to get started writing UI tests.
33 | // Use XCTAssert and related functions to verify your tests produce the correct results.
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/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 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/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 | }
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // VPCollectionViewLayoutExample
4 | //
5 | // Created by Varun P M on 05/11/17.
6 | // Copyright © 2017 Varun P M. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VPCollectionViewLayout
2 |
3 | VPCollectionViewLayout is a helper class for displaying collection view cells in different flow layouts. The UI can be customized in different ways. See `Usage` for more info.
4 |
5 | ## Requirements
6 |
7 | 1. iOS 9.0 or later.
8 | 2. ARC memory management.
9 |
10 | ## Usage
11 |
12 | Drag and drop the folder `VPCollectionViewLayout` into your project. Add a collection view wherever needed in your xib or storyboard and change the flow layout class to custom and enter the name of the class as `VPCollectionViewLayout`.
13 |
14 | The currently supported layouts are - vertical, horizontal, centralizedVertical, centralizedHorizontal and circular (more detail explanation mentioned within the class).
15 |
16 |
17 | # 
18 | # 
19 | # 
20 | # 
21 | # 
22 | # 
23 |
24 | ## Contributing
25 | **Type - 1**
26 |
27 | 1. Fork it!
28 | 2. Create your feature branch: `git checkout -b my-new-feature`
29 | 3. Commit your changes: `git commit -am 'Add some feature'`
30 | 4. Push to the branch: `git push origin my-new-feature`
31 | 5. Submit a pull request :D
32 |
33 | **Type - 2**
34 |
35 | 1. Create an issue/explain the needed flowlayout
36 | 2. I'll try to add the necessry feature
37 | 3. You can download the update code :P
38 |
39 | ## History
40 |
41 | ### Version 0.2.1
42 |
43 | Added sample images and set default layout to be vertical
44 |
45 | ### Version 0.2.0
46 |
47 | Added support for circular flow layout
48 |
49 | ### Version 0.1.0
50 |
51 | Added support for 4 types of flow layout display as well as selection animation handled with animation.
52 |
53 |
54 | ## License
55 | MIT License
56 |
57 | Copyright (c) 2017 Varun P M
58 |
59 | Permission is hereby granted, free of charge, to any person obtaining a copy
60 | of this software and associated documentation files (the "Software"), to deal
61 | in the Software without restriction, including without limitation the rights
62 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
63 | copies of the Software, and to permit persons to whom the Software is
64 | furnished to do so, subject to the following conditions:
65 |
66 | The above copyright notice and this permission notice shall be included in all
67 | copies or substantial portions of the Software.
68 |
69 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
72 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
73 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
74 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
75 | SOFTWARE.
76 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // VPCollectionViewLayoutExample
4 | //
5 | // Created by Varun P M on 05/11/17.
6 | // Copyright © 2017 Varun P M. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | @IBOutlet weak var sampleCollectionView: UICollectionView!
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | // Do any additional setup after loading the view, typically from a nib.
18 |
19 | sampleCollectionView.register(UINib(nibName: String(describing: SampleCollectionViewCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: SampleCollectionViewCell.self))
20 | }
21 |
22 | override func didReceiveMemoryWarning() {
23 | super.didReceiveMemoryWarning()
24 | // Dispose of any resources that can be recreated.
25 | }
26 | }
27 |
28 | extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
29 | func numberOfSections(in collectionView: UICollectionView) -> Int {
30 | return 1
31 | }
32 |
33 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
34 | return 10
35 | }
36 |
37 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
38 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: SampleCollectionViewCell.self), for: indexPath) as! SampleCollectionViewCell
39 |
40 | // cell.cellTitleLabel.text = "\(indexPath.item + 1)"
41 | cell.cellImageView.image = UIImage(named: "sample-\(indexPath.item + 1)")
42 |
43 | return cell
44 | }
45 |
46 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
47 | (collectionView.collectionViewLayout as! VPCollectionViewLayout).didSelectCell(atIndexPath: indexPath)
48 | }
49 |
50 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
51 | return CGSize(width: 150, height: 150)
52 | }
53 |
54 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
55 | return 20
56 | }
57 |
58 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
59 | return 10
60 | }
61 |
62 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
63 | return UIEdgeInsets(top: 25, left: 25, bottom: 25, right: 25)
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample/SampleCollectionViewCell.xib:
--------------------------------------------------------------------------------
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 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/VPCollectionViewLayout/VPCollectionViewLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VPCollectionViewLayout.swift
3 | // VPCollectionViewLayoutExample
4 | // Version 0.1.0
5 | //
6 | // Created by Varun P M on 05/11/17.
7 | // Copyright © 2017 Varun P M. All rights reserved.
8 | //
9 | //
10 | // MIT License
11 | //
12 | // Copyright (c) 2017 Varun P M
13 | //
14 | // Permission is hereby granted, free of charge, to any person obtaining a copy
15 | // of this software and associated documentation files (the "Software"), to deal
16 | // in the Software without restriction, including without limitation the rights
17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 | // copies of the Software, and to permit persons to whom the Software is
19 | // furnished to do so, subject to the following conditions:
20 | //
21 | // The above copyright notice and this permission notice shall be included in all
22 | // copies or substantial portions of the Software.
23 | //
24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 | // SOFTWARE.
31 |
32 | import UIKit
33 |
34 | class VPCollectionViewLayout: UICollectionViewFlowLayout {
35 | // Enum that contains all possible combination of layout type
36 | enum CollectionViewLayoutType {
37 | /// If vertical flow, then the cells will be placed horizontally first until it fits the current collectionView's width. If the cell doesn't fit, then it'll be moved to next row and same flow follows for remaining cells. If there is a new section, then the cell will be forced to the next row forcefully.
38 | case vertical
39 |
40 | /// If horizontal flow, then the cells will be placed vertically first until it fits the current collectionView's height. If the cell doesn't fit, then it'll be moved to next column and same flow follows for remaining cells. If there is a new section, then the cell will be forced to the next column forcefully.
41 | case horizontal
42 |
43 | /// If centralized flow, then the cells will be placed centered and vertically and will be adjusted to accomodate as much as possible.
44 | /// - Note: The cell's height for all the cell within a section has to be constant for this to look good.
45 | case centralizedVertical
46 |
47 | /// If centralized flow, then the cells will be placed centered and horizontally and will be adjusted to accomodate as much as possible.
48 | /// - Note: The cell's width for all the cell within a section has to be constant for this to look good.
49 | case centralizedHorizontal
50 |
51 | /// If circular flow, then the cells will be placed circularly and will be adjusted to accomodate as much as possible.
52 | /// - Note: This will place the cell in round table format and doesn't rotate the cell itself. Also this layout assumes that all the cell's are of same size. Different sized cells are not supported.
53 | case circular
54 | }
55 |
56 | /// Set the required layout type from the defined set of types. Defaults to vertical
57 | var layoutType: CollectionViewLayoutType = .vertical
58 |
59 | /// The radius to be used for circular layout. Defaults to 100
60 | var circularRadius: CGFloat = 100
61 |
62 | // This variable is used if a cell has to be expanded when selecting pushing other nearby cells maintaining the same spacing
63 | private var selectedIndexPath: IndexPath?
64 |
65 | // This variable is used only if `selectedIndexPath` is set. This variable takes values by which the size has to be increased or decreased for the selected cell. The values should be in range between 0 (decrease to 0) to +ve (increase by any value)
66 | private var selectedCellExpandPercentage: CGSize = CGSize(width: 1, height: 1)
67 |
68 | // Stored calculated attributes for caching purpose
69 | private var layoutAttributes: [UICollectionViewLayoutAttributes] = []
70 | private var maxContentWidth: CGFloat = 0
71 | private var maxContentHeight: CGFloat = 0
72 |
73 | override func prepare() {
74 | layoutAttributes.removeAll()
75 | calculateLayoutAttributes()
76 | }
77 |
78 | override var collectionViewContentSize: CGSize {
79 | return CGSize(width: maxContentWidth, height: maxContentHeight)
80 | }
81 |
82 | /// Call this method when selection of cell should expand the cell with/without animation
83 | ///
84 | /// - Parameters:
85 | /// - indexPath: the indexpath of the cell whose size has to be increased or decreased. If set to nil, the size will return to default size if there are any previously selected cells.
86 | /// - percentageIncrease: the size increase in percentage/100 format for the selected cell. If width and height are 1 & 1, then default size. If greater than 1, then it's increased size and vice-versa. Defaults to 1.25 each (125% of the current size).
87 | /// - shouldAnimate: optional bool variable to animate selection if needed. Defaults to `true`.
88 | func didSelectCell(atIndexPath indexPath: IndexPath?, percentageIncrease: CGSize = CGSize(width: 1.25, height: 1.25), shouldAnimate: Bool = true) {
89 | selectedIndexPath = indexPath
90 | selectedCellExpandPercentage = percentageIncrease
91 |
92 | if shouldAnimate {
93 | collectionView?.performBatchUpdates({ [weak self] in
94 | self?.invalidateLayout()
95 | }, completion: nil)
96 | }
97 | else {
98 | invalidateLayout()
99 | }
100 | }
101 |
102 | // Calculate the attributes when invalidating layout
103 | private func calculateLayoutAttributes() {
104 | guard let collectionView = collectionView else {
105 | return
106 | }
107 |
108 | maxContentWidth = 0
109 | maxContentHeight = 0
110 |
111 | var adjustedInsets: CGFloat = 0
112 | if #available(iOS 11, *) {
113 | adjustedInsets = collectionView.adjustedContentInset.top
114 | }
115 |
116 | let adjustedCollectionViewHeight = collectionView.bounds.size.height - adjustedInsets
117 | var startXPosition: CGFloat = 0
118 | var startYPosition: CGFloat = 0
119 | var availableWidth: CGFloat = collectionView.bounds.size.width
120 | var availableHeight: CGFloat = adjustedCollectionViewHeight
121 | var angle: CGFloat = 0
122 |
123 | for sectionIndex in stride(from: 0, to: collectionView.numberOfSections, by: 1) {
124 | // Fetch the default values for spacing, if set
125 | var defaultSectionInsets: UIEdgeInsets = sectionInset
126 | var defaultInterItemSpacing: CGFloat = minimumInteritemSpacing
127 | var defaultLineSpacing: CGFloat = minimumLineSpacing
128 |
129 | if let delagteFlowLayout = collectionView.delegate as? UICollectionViewDelegateFlowLayout {
130 | // Get the insets from the controller/view if the insets delegate has been implemented
131 | if delagteFlowLayout.responds(to: #selector(delagteFlowLayout.collectionView(_:layout:insetForSectionAt:))) {
132 | defaultSectionInsets = delagteFlowLayout.collectionView!(collectionView, layout: self, insetForSectionAt: sectionIndex)
133 | }
134 |
135 | // Get the inter item spacing from the controller/view if the inter item spacing delegate has been implemented
136 | if delagteFlowLayout.responds(to: #selector(delagteFlowLayout.collectionView(_:layout:minimumInteritemSpacingForSectionAt:))) {
137 | defaultInterItemSpacing = delagteFlowLayout.collectionView!(collectionView, layout: self, minimumInteritemSpacingForSectionAt: sectionIndex)
138 | }
139 |
140 | // Get the line spacing from the controller/view if the line spacing delegate has been implemented
141 | if delagteFlowLayout.responds(to: #selector(delagteFlowLayout.collectionView(_:layout:minimumLineSpacingForSectionAt:))) {
142 | defaultLineSpacing = delagteFlowLayout.collectionView!(collectionView, layout: self, minimumLineSpacingForSectionAt: sectionIndex)
143 | }
144 | }
145 |
146 | // Update content variables based on layout type
147 | switch layoutType {
148 | case .vertical, .centralizedVertical:
149 | startYPosition += defaultSectionInsets.top
150 | startXPosition = defaultSectionInsets.left
151 | maxContentHeight += defaultSectionInsets.top
152 | availableWidth = (collectionView.bounds.size.width - defaultSectionInsets.left - defaultSectionInsets.right)
153 | case .horizontal, .centralizedHorizontal:
154 | startXPosition += defaultSectionInsets.left
155 | startYPosition = defaultSectionInsets.top
156 | maxContentWidth += defaultSectionInsets.left
157 | availableHeight = (adjustedCollectionViewHeight - defaultSectionInsets.top - defaultSectionInsets.bottom)
158 | case .circular:
159 | angle = 2 * CGFloat.pi / CGFloat(collectionView.numberOfItems(inSection: sectionIndex))
160 | }
161 |
162 | for itemIndex in stride(from: 0, to: collectionView.numberOfItems(inSection: sectionIndex), by: 1) {
163 | let indexPath = IndexPath(item: itemIndex, section: sectionIndex)
164 | let layoutAttribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
165 | var itemSize: CGSize = CGSize.zero
166 |
167 | // Get the item size from the controller/view if the itemSize delegate has been implemented
168 | if let delagteFlowLayout = collectionView.delegate as? UICollectionViewDelegateFlowLayout {
169 | if delagteFlowLayout.responds(to: #selector(delagteFlowLayout.collectionView(_:layout:sizeForItemAt:))) {
170 | itemSize = delagteFlowLayout.collectionView!(collectionView, layout: self, sizeForItemAt: indexPath)
171 |
172 | if selectedIndexPath == indexPath {
173 | layoutAttribute.frame.size = CGSize(width: itemSize.width * selectedCellExpandPercentage.width, height: itemSize.height * selectedCellExpandPercentage.width)
174 | }
175 | else {
176 | layoutAttribute.frame.size = itemSize
177 | }
178 | }
179 | }
180 |
181 | // Calculate the proper layout for each cases
182 | switch layoutType {
183 | case .vertical, .centralizedVertical:
184 | if layoutType == .centralizedVertical {
185 | // Check if the cell can be placed in the same row. If not, then increase Y position for height related values and update frame
186 | availableWidth -= layoutAttribute.frame.size.width
187 |
188 | // Remove padding only if it's not a first cell
189 | if itemIndex != 0 {
190 | availableWidth -= defaultInterItemSpacing
191 | }
192 |
193 | if availableWidth >= 0 {
194 | // Loop through all attributes in reverse order to identify attribute that is in same row. Then reposition all attributes centered and place the current attribute again
195 | for attribute in layoutAttributes.reversed() {
196 | if attribute.frame.origin.y != startYPosition {
197 | break
198 | }
199 |
200 | // Adjust the attribute that lie in same line so as to make it center aligned
201 | attribute.frame.origin.x -= (defaultInterItemSpacing + layoutAttribute.frame.size.width) / 2
202 | }
203 |
204 | // If not first index, then get X value of last attribute and add spacing to get next X position. Else get X position w.r.t collectionView width
205 | if itemIndex != 0 {
206 | startXPosition = layoutAttributes.last!.frame.maxX + defaultInterItemSpacing
207 | }
208 | else {
209 | startXPosition = (collectionView.bounds.size.width - layoutAttribute.frame.size.width) / 2
210 | }
211 | }
212 | else {
213 | // Move to next row and set necessary values
214 | availableWidth = collectionView.bounds.size.width - defaultSectionInsets.left - defaultSectionInsets.right - layoutAttribute.frame.size.width
215 | startXPosition = (collectionView.bounds.size.width - layoutAttribute.frame.size.width) / 2
216 | startYPosition = maxContentHeight + defaultLineSpacing
217 | }
218 | }
219 | else {
220 | if (startXPosition + defaultInterItemSpacing + layoutAttribute.frame.size.width + defaultSectionInsets.right) <= collectionView.bounds.size.width {
221 | // Add spacing only if it's not a first cell
222 | if itemIndex != 0 {
223 | startXPosition += defaultInterItemSpacing
224 | }
225 | }
226 | else {
227 | startXPosition = defaultSectionInsets.left
228 | startYPosition = maxContentHeight + defaultLineSpacing
229 | }
230 | }
231 |
232 | // Update frame origin
233 | layoutAttribute.frame.origin = CGPoint(x: startXPosition, y: startYPosition)
234 | startXPosition = layoutAttribute.frame.maxX
235 |
236 | // Get max height for collectionView
237 | maxContentHeight = max(maxContentHeight, layoutAttribute.frame.maxY)
238 |
239 | // If the item is the last item, then add the bottom insets for the section
240 | if itemIndex == (collectionView.numberOfItems(inSection: sectionIndex) - 1) {
241 | maxContentHeight += defaultSectionInsets.bottom
242 | startYPosition = maxContentHeight
243 | }
244 |
245 | // Width doesn't increase here
246 | maxContentWidth = collectionView.bounds.size.width
247 | case .horizontal, .centralizedHorizontal:
248 | if layoutType == .centralizedHorizontal {
249 | // Check if the cell can be placed in the same column. If not, then increase X position for width related values and update frame
250 | availableHeight -= layoutAttribute.frame.size.height
251 |
252 | // Remove padding only if it's not a first cell
253 | if itemIndex != 0 {
254 | availableHeight -= defaultInterItemSpacing
255 | }
256 |
257 | if availableHeight >= 0 {
258 | // Loop through all attributes in reverse order to identify attribute that is in same column. Then reposition all attributes centered and place the current attribute again
259 | for attribute in layoutAttributes.reversed() {
260 | if attribute.frame.origin.x != startXPosition {
261 | break
262 | }
263 |
264 | // Adjust the attribute that lie in same line so as to make it center aligned
265 | attribute.frame.origin.y -= (defaultInterItemSpacing + layoutAttribute.frame.size.height) / 2
266 | }
267 |
268 | // If not first index, then get Y value of last attribute and add spacing to get next Y position. Else get Y position w.r.t collectionView height
269 | if itemIndex != 0 {
270 | startYPosition = layoutAttributes.last!.frame.maxY + defaultInterItemSpacing
271 | }
272 | else {
273 | startYPosition = (adjustedCollectionViewHeight - layoutAttribute.frame.size.height) / 2
274 | }
275 | }
276 | else {
277 | // Move to next column and set necessary values
278 | availableHeight = adjustedCollectionViewHeight - defaultSectionInsets.top - defaultSectionInsets.bottom - layoutAttribute.frame.size.height
279 | startYPosition = (adjustedCollectionViewHeight - layoutAttribute.frame.size.height) / 2
280 | startXPosition = maxContentWidth + defaultLineSpacing
281 | }
282 | }
283 | else {
284 | // Check if the cell can be placed in the same column. If not, then increase X position for width related values and update frame
285 | if (startYPosition + defaultInterItemSpacing + layoutAttribute.frame.size.height + defaultSectionInsets.bottom) <= adjustedCollectionViewHeight {
286 | // Add spacing only if it's not a first cell
287 | if itemIndex != 0 {
288 | startYPosition += defaultInterItemSpacing
289 | }
290 | }
291 | else {
292 | startYPosition = defaultSectionInsets.top
293 | startXPosition = maxContentWidth + defaultLineSpacing
294 | }
295 | }
296 |
297 | // Update frame origin
298 | layoutAttribute.frame.origin = CGPoint(x: startXPosition, y: startYPosition)
299 | startYPosition = layoutAttribute.frame.maxY
300 |
301 | // Get max width for collectionView
302 | maxContentWidth = max(maxContentWidth, layoutAttribute.frame.maxX)
303 |
304 | // If the item is the last item, then add the bottom insets for the section
305 | if itemIndex == (collectionView.numberOfItems(inSection: sectionIndex) - 1) {
306 | maxContentWidth += defaultSectionInsets.right
307 | startXPosition = maxContentWidth
308 | }
309 |
310 | // Height doesn't increase here
311 | maxContentHeight = adjustedCollectionViewHeight
312 | case .circular:
313 | // Since max content width would be diameter of circle + left and right section insets + cell's size (left and right cell will be clipped to half since placed at center)
314 | maxContentWidth = 2 * circularRadius + layoutAttribute.frame.size.width + defaultSectionInsets.left + defaultSectionInsets.right
315 |
316 | // Since max content height would be diameter of circle + top and bottom section insets + cell's size (top and bottom cell will be clipped to half since placed at center)
317 | maxContentHeight = 2 * circularRadius + layoutAttribute.frame.size.height + defaultSectionInsets.top + defaultSectionInsets.bottom
318 |
319 | // If the selected index path is the same as the current index path, then the cell is expanded. So get the increased size to calculate padding
320 | let increasedPaddingSize: CGSize = CGSize(width: (layoutAttribute.frame.size.width - itemSize.width) / 2, height: (layoutAttribute.frame.size.height - itemSize.height) / 2)
321 |
322 | // Calculate the position for the layout attribute
323 | let actualAngle = CGFloat(itemIndex) * angle
324 | let xPositionPadding = circularRadius + defaultSectionInsets.left - increasedPaddingSize.width
325 | let yPositionPadding = circularRadius + defaultSectionInsets.top - increasedPaddingSize.height
326 | layoutAttribute.frame.origin = CGPoint(x: xPositionPadding + circularRadius * cos(actualAngle), y: yPositionPadding + circularRadius * sin(actualAngle))
327 | }
328 |
329 | layoutAttributes.append(layoutAttribute)
330 | }
331 | }
332 | }
333 |
334 | override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
335 | return false
336 | }
337 |
338 | override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
339 | var matchingLayoutAttributes = [UICollectionViewLayoutAttributes]()
340 |
341 | for attribute in layoutAttributes {
342 | if attribute.frame.intersects(rect) {
343 | matchingLayoutAttributes.append(attribute)
344 | }
345 | }
346 |
347 | return matchingLayoutAttributes
348 | }
349 | }
350 |
--------------------------------------------------------------------------------
/VPCollectionViewLayoutExample/VPCollectionViewLayoutExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 8B33BD191FAEFE81002046F2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B33BD181FAEFE81002046F2 /* AppDelegate.swift */; };
11 | 8B33BD1B1FAEFE81002046F2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B33BD1A1FAEFE81002046F2 /* ViewController.swift */; };
12 | 8B33BD1E1FAEFE81002046F2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8B33BD1C1FAEFE81002046F2 /* Main.storyboard */; };
13 | 8B33BD201FAEFE81002046F2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8B33BD1F1FAEFE81002046F2 /* Assets.xcassets */; };
14 | 8B33BD231FAEFE81002046F2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8B33BD211FAEFE81002046F2 /* LaunchScreen.storyboard */; };
15 | 8B33BD2E1FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B33BD2D1FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests.swift */; };
16 | 8B33BD391FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B33BD381FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests.swift */; };
17 | 8B33BD481FAEFF10002046F2 /* VPCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B33BD471FAEFF10002046F2 /* VPCollectionViewLayout.swift */; };
18 | 8B33BD4B1FAF01A1002046F2 /* SampleCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B33BD491FAF01A1002046F2 /* SampleCollectionViewCell.swift */; };
19 | 8B33BD4C1FAF01A1002046F2 /* SampleCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8B33BD4A1FAF01A1002046F2 /* SampleCollectionViewCell.xib */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXContainerItemProxy section */
23 | 8B33BD2A1FAEFE81002046F2 /* PBXContainerItemProxy */ = {
24 | isa = PBXContainerItemProxy;
25 | containerPortal = 8B33BD0D1FAEFE81002046F2 /* Project object */;
26 | proxyType = 1;
27 | remoteGlobalIDString = 8B33BD141FAEFE81002046F2;
28 | remoteInfo = VPCollectionViewLayoutExample;
29 | };
30 | 8B33BD351FAEFE81002046F2 /* PBXContainerItemProxy */ = {
31 | isa = PBXContainerItemProxy;
32 | containerPortal = 8B33BD0D1FAEFE81002046F2 /* Project object */;
33 | proxyType = 1;
34 | remoteGlobalIDString = 8B33BD141FAEFE81002046F2;
35 | remoteInfo = VPCollectionViewLayoutExample;
36 | };
37 | /* End PBXContainerItemProxy section */
38 |
39 | /* Begin PBXFileReference section */
40 | 8B33BD151FAEFE81002046F2 /* VPCollectionViewLayoutExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VPCollectionViewLayoutExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 8B33BD181FAEFE81002046F2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
42 | 8B33BD1A1FAEFE81002046F2 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
43 | 8B33BD1D1FAEFE81002046F2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
44 | 8B33BD1F1FAEFE81002046F2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
45 | 8B33BD221FAEFE81002046F2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
46 | 8B33BD241FAEFE81002046F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
47 | 8B33BD291FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VPCollectionViewLayoutExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
48 | 8B33BD2D1FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCollectionViewLayoutExampleTests.swift; sourceTree = ""; };
49 | 8B33BD2F1FAEFE81002046F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
50 | 8B33BD341FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VPCollectionViewLayoutExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
51 | 8B33BD381FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCollectionViewLayoutExampleUITests.swift; sourceTree = ""; };
52 | 8B33BD3A1FAEFE81002046F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
53 | 8B33BD471FAEFF10002046F2 /* VPCollectionViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCollectionViewLayout.swift; sourceTree = ""; };
54 | 8B33BD491FAF01A1002046F2 /* SampleCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleCollectionViewCell.swift; sourceTree = ""; };
55 | 8B33BD4A1FAF01A1002046F2 /* SampleCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SampleCollectionViewCell.xib; sourceTree = ""; };
56 | /* End PBXFileReference section */
57 |
58 | /* Begin PBXFrameworksBuildPhase section */
59 | 8B33BD121FAEFE81002046F2 /* Frameworks */ = {
60 | isa = PBXFrameworksBuildPhase;
61 | buildActionMask = 2147483647;
62 | files = (
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | 8B33BD261FAEFE81002046F2 /* Frameworks */ = {
67 | isa = PBXFrameworksBuildPhase;
68 | buildActionMask = 2147483647;
69 | files = (
70 | );
71 | runOnlyForDeploymentPostprocessing = 0;
72 | };
73 | 8B33BD311FAEFE81002046F2 /* Frameworks */ = {
74 | isa = PBXFrameworksBuildPhase;
75 | buildActionMask = 2147483647;
76 | files = (
77 | );
78 | runOnlyForDeploymentPostprocessing = 0;
79 | };
80 | /* End PBXFrameworksBuildPhase section */
81 |
82 | /* Begin PBXGroup section */
83 | 8B33BD0C1FAEFE81002046F2 = {
84 | isa = PBXGroup;
85 | children = (
86 | 8B33BD171FAEFE81002046F2 /* VPCollectionViewLayoutExample */,
87 | 8B33BD2C1FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests */,
88 | 8B33BD371FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests */,
89 | 8B33BD161FAEFE81002046F2 /* Products */,
90 | );
91 | sourceTree = "";
92 | };
93 | 8B33BD161FAEFE81002046F2 /* Products */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 8B33BD151FAEFE81002046F2 /* VPCollectionViewLayoutExample.app */,
97 | 8B33BD291FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests.xctest */,
98 | 8B33BD341FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests.xctest */,
99 | );
100 | name = Products;
101 | sourceTree = "";
102 | };
103 | 8B33BD171FAEFE81002046F2 /* VPCollectionViewLayoutExample */ = {
104 | isa = PBXGroup;
105 | children = (
106 | 8B33BD181FAEFE81002046F2 /* AppDelegate.swift */,
107 | 8B33BD461FAEFEE8002046F2 /* VPCollectionViewLayout */,
108 | 8B33BD1A1FAEFE81002046F2 /* ViewController.swift */,
109 | 8B33BD491FAF01A1002046F2 /* SampleCollectionViewCell.swift */,
110 | 8B33BD4A1FAF01A1002046F2 /* SampleCollectionViewCell.xib */,
111 | 8B33BD1C1FAEFE81002046F2 /* Main.storyboard */,
112 | 8B33BD1F1FAEFE81002046F2 /* Assets.xcassets */,
113 | 8B33BD211FAEFE81002046F2 /* LaunchScreen.storyboard */,
114 | 8B33BD241FAEFE81002046F2 /* Info.plist */,
115 | );
116 | path = VPCollectionViewLayoutExample;
117 | sourceTree = "";
118 | };
119 | 8B33BD2C1FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests */ = {
120 | isa = PBXGroup;
121 | children = (
122 | 8B33BD2D1FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests.swift */,
123 | 8B33BD2F1FAEFE81002046F2 /* Info.plist */,
124 | );
125 | path = VPCollectionViewLayoutExampleTests;
126 | sourceTree = "";
127 | };
128 | 8B33BD371FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests */ = {
129 | isa = PBXGroup;
130 | children = (
131 | 8B33BD381FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests.swift */,
132 | 8B33BD3A1FAEFE81002046F2 /* Info.plist */,
133 | );
134 | path = VPCollectionViewLayoutExampleUITests;
135 | sourceTree = "";
136 | };
137 | 8B33BD461FAEFEE8002046F2 /* VPCollectionViewLayout */ = {
138 | isa = PBXGroup;
139 | children = (
140 | 8B33BD471FAEFF10002046F2 /* VPCollectionViewLayout.swift */,
141 | );
142 | name = VPCollectionViewLayout;
143 | path = ../../VPCollectionViewLayout;
144 | sourceTree = "";
145 | };
146 | /* End PBXGroup section */
147 |
148 | /* Begin PBXNativeTarget section */
149 | 8B33BD141FAEFE81002046F2 /* VPCollectionViewLayoutExample */ = {
150 | isa = PBXNativeTarget;
151 | buildConfigurationList = 8B33BD3D1FAEFE81002046F2 /* Build configuration list for PBXNativeTarget "VPCollectionViewLayoutExample" */;
152 | buildPhases = (
153 | 8B33BD111FAEFE81002046F2 /* Sources */,
154 | 8B33BD121FAEFE81002046F2 /* Frameworks */,
155 | 8B33BD131FAEFE81002046F2 /* Resources */,
156 | );
157 | buildRules = (
158 | );
159 | dependencies = (
160 | );
161 | name = VPCollectionViewLayoutExample;
162 | productName = VPCollectionViewLayoutExample;
163 | productReference = 8B33BD151FAEFE81002046F2 /* VPCollectionViewLayoutExample.app */;
164 | productType = "com.apple.product-type.application";
165 | };
166 | 8B33BD281FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests */ = {
167 | isa = PBXNativeTarget;
168 | buildConfigurationList = 8B33BD401FAEFE81002046F2 /* Build configuration list for PBXNativeTarget "VPCollectionViewLayoutExampleTests" */;
169 | buildPhases = (
170 | 8B33BD251FAEFE81002046F2 /* Sources */,
171 | 8B33BD261FAEFE81002046F2 /* Frameworks */,
172 | 8B33BD271FAEFE81002046F2 /* Resources */,
173 | );
174 | buildRules = (
175 | );
176 | dependencies = (
177 | 8B33BD2B1FAEFE81002046F2 /* PBXTargetDependency */,
178 | );
179 | name = VPCollectionViewLayoutExampleTests;
180 | productName = VPCollectionViewLayoutExampleTests;
181 | productReference = 8B33BD291FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests.xctest */;
182 | productType = "com.apple.product-type.bundle.unit-test";
183 | };
184 | 8B33BD331FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests */ = {
185 | isa = PBXNativeTarget;
186 | buildConfigurationList = 8B33BD431FAEFE81002046F2 /* Build configuration list for PBXNativeTarget "VPCollectionViewLayoutExampleUITests" */;
187 | buildPhases = (
188 | 8B33BD301FAEFE81002046F2 /* Sources */,
189 | 8B33BD311FAEFE81002046F2 /* Frameworks */,
190 | 8B33BD321FAEFE81002046F2 /* Resources */,
191 | );
192 | buildRules = (
193 | );
194 | dependencies = (
195 | 8B33BD361FAEFE81002046F2 /* PBXTargetDependency */,
196 | );
197 | name = VPCollectionViewLayoutExampleUITests;
198 | productName = VPCollectionViewLayoutExampleUITests;
199 | productReference = 8B33BD341FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests.xctest */;
200 | productType = "com.apple.product-type.bundle.ui-testing";
201 | };
202 | /* End PBXNativeTarget section */
203 |
204 | /* Begin PBXProject section */
205 | 8B33BD0D1FAEFE81002046F2 /* Project object */ = {
206 | isa = PBXProject;
207 | attributes = {
208 | LastSwiftUpdateCheck = 0900;
209 | LastUpgradeCheck = 0900;
210 | ORGANIZATIONNAME = "Varun P M";
211 | TargetAttributes = {
212 | 8B33BD141FAEFE81002046F2 = {
213 | CreatedOnToolsVersion = 9.0;
214 | ProvisioningStyle = Manual;
215 | };
216 | 8B33BD281FAEFE81002046F2 = {
217 | CreatedOnToolsVersion = 9.0;
218 | ProvisioningStyle = Automatic;
219 | TestTargetID = 8B33BD141FAEFE81002046F2;
220 | };
221 | 8B33BD331FAEFE81002046F2 = {
222 | CreatedOnToolsVersion = 9.0;
223 | ProvisioningStyle = Automatic;
224 | TestTargetID = 8B33BD141FAEFE81002046F2;
225 | };
226 | };
227 | };
228 | buildConfigurationList = 8B33BD101FAEFE81002046F2 /* Build configuration list for PBXProject "VPCollectionViewLayoutExample" */;
229 | compatibilityVersion = "Xcode 8.0";
230 | developmentRegion = en;
231 | hasScannedForEncodings = 0;
232 | knownRegions = (
233 | en,
234 | Base,
235 | );
236 | mainGroup = 8B33BD0C1FAEFE81002046F2;
237 | productRefGroup = 8B33BD161FAEFE81002046F2 /* Products */;
238 | projectDirPath = "";
239 | projectRoot = "";
240 | targets = (
241 | 8B33BD141FAEFE81002046F2 /* VPCollectionViewLayoutExample */,
242 | 8B33BD281FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests */,
243 | 8B33BD331FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests */,
244 | );
245 | };
246 | /* End PBXProject section */
247 |
248 | /* Begin PBXResourcesBuildPhase section */
249 | 8B33BD131FAEFE81002046F2 /* Resources */ = {
250 | isa = PBXResourcesBuildPhase;
251 | buildActionMask = 2147483647;
252 | files = (
253 | 8B33BD231FAEFE81002046F2 /* LaunchScreen.storyboard in Resources */,
254 | 8B33BD201FAEFE81002046F2 /* Assets.xcassets in Resources */,
255 | 8B33BD4C1FAF01A1002046F2 /* SampleCollectionViewCell.xib in Resources */,
256 | 8B33BD1E1FAEFE81002046F2 /* Main.storyboard in Resources */,
257 | );
258 | runOnlyForDeploymentPostprocessing = 0;
259 | };
260 | 8B33BD271FAEFE81002046F2 /* Resources */ = {
261 | isa = PBXResourcesBuildPhase;
262 | buildActionMask = 2147483647;
263 | files = (
264 | );
265 | runOnlyForDeploymentPostprocessing = 0;
266 | };
267 | 8B33BD321FAEFE81002046F2 /* Resources */ = {
268 | isa = PBXResourcesBuildPhase;
269 | buildActionMask = 2147483647;
270 | files = (
271 | );
272 | runOnlyForDeploymentPostprocessing = 0;
273 | };
274 | /* End PBXResourcesBuildPhase section */
275 |
276 | /* Begin PBXSourcesBuildPhase section */
277 | 8B33BD111FAEFE81002046F2 /* Sources */ = {
278 | isa = PBXSourcesBuildPhase;
279 | buildActionMask = 2147483647;
280 | files = (
281 | 8B33BD1B1FAEFE81002046F2 /* ViewController.swift in Sources */,
282 | 8B33BD481FAEFF10002046F2 /* VPCollectionViewLayout.swift in Sources */,
283 | 8B33BD4B1FAF01A1002046F2 /* SampleCollectionViewCell.swift in Sources */,
284 | 8B33BD191FAEFE81002046F2 /* AppDelegate.swift in Sources */,
285 | );
286 | runOnlyForDeploymentPostprocessing = 0;
287 | };
288 | 8B33BD251FAEFE81002046F2 /* Sources */ = {
289 | isa = PBXSourcesBuildPhase;
290 | buildActionMask = 2147483647;
291 | files = (
292 | 8B33BD2E1FAEFE81002046F2 /* VPCollectionViewLayoutExampleTests.swift in Sources */,
293 | );
294 | runOnlyForDeploymentPostprocessing = 0;
295 | };
296 | 8B33BD301FAEFE81002046F2 /* Sources */ = {
297 | isa = PBXSourcesBuildPhase;
298 | buildActionMask = 2147483647;
299 | files = (
300 | 8B33BD391FAEFE81002046F2 /* VPCollectionViewLayoutExampleUITests.swift in Sources */,
301 | );
302 | runOnlyForDeploymentPostprocessing = 0;
303 | };
304 | /* End PBXSourcesBuildPhase section */
305 |
306 | /* Begin PBXTargetDependency section */
307 | 8B33BD2B1FAEFE81002046F2 /* PBXTargetDependency */ = {
308 | isa = PBXTargetDependency;
309 | target = 8B33BD141FAEFE81002046F2 /* VPCollectionViewLayoutExample */;
310 | targetProxy = 8B33BD2A1FAEFE81002046F2 /* PBXContainerItemProxy */;
311 | };
312 | 8B33BD361FAEFE81002046F2 /* PBXTargetDependency */ = {
313 | isa = PBXTargetDependency;
314 | target = 8B33BD141FAEFE81002046F2 /* VPCollectionViewLayoutExample */;
315 | targetProxy = 8B33BD351FAEFE81002046F2 /* PBXContainerItemProxy */;
316 | };
317 | /* End PBXTargetDependency section */
318 |
319 | /* Begin PBXVariantGroup section */
320 | 8B33BD1C1FAEFE81002046F2 /* Main.storyboard */ = {
321 | isa = PBXVariantGroup;
322 | children = (
323 | 8B33BD1D1FAEFE81002046F2 /* Base */,
324 | );
325 | name = Main.storyboard;
326 | sourceTree = "";
327 | };
328 | 8B33BD211FAEFE81002046F2 /* LaunchScreen.storyboard */ = {
329 | isa = PBXVariantGroup;
330 | children = (
331 | 8B33BD221FAEFE81002046F2 /* Base */,
332 | );
333 | name = LaunchScreen.storyboard;
334 | sourceTree = "";
335 | };
336 | /* End PBXVariantGroup section */
337 |
338 | /* Begin XCBuildConfiguration section */
339 | 8B33BD3B1FAEFE81002046F2 /* Debug */ = {
340 | isa = XCBuildConfiguration;
341 | buildSettings = {
342 | ALWAYS_SEARCH_USER_PATHS = NO;
343 | CLANG_ANALYZER_NONNULL = YES;
344 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
345 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
346 | CLANG_CXX_LIBRARY = "libc++";
347 | CLANG_ENABLE_MODULES = YES;
348 | CLANG_ENABLE_OBJC_ARC = YES;
349 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
350 | CLANG_WARN_BOOL_CONVERSION = YES;
351 | CLANG_WARN_COMMA = YES;
352 | CLANG_WARN_CONSTANT_CONVERSION = YES;
353 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
354 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
355 | CLANG_WARN_EMPTY_BODY = YES;
356 | CLANG_WARN_ENUM_CONVERSION = YES;
357 | CLANG_WARN_INFINITE_RECURSION = YES;
358 | CLANG_WARN_INT_CONVERSION = YES;
359 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
360 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
361 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
362 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
363 | CLANG_WARN_STRICT_PROTOTYPES = YES;
364 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
365 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
366 | CLANG_WARN_UNREACHABLE_CODE = YES;
367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
368 | CODE_SIGN_IDENTITY = "iPhone Developer";
369 | COPY_PHASE_STRIP = NO;
370 | DEBUG_INFORMATION_FORMAT = dwarf;
371 | ENABLE_STRICT_OBJC_MSGSEND = YES;
372 | ENABLE_TESTABILITY = YES;
373 | GCC_C_LANGUAGE_STANDARD = gnu11;
374 | GCC_DYNAMIC_NO_PIC = NO;
375 | GCC_NO_COMMON_BLOCKS = YES;
376 | GCC_OPTIMIZATION_LEVEL = 0;
377 | GCC_PREPROCESSOR_DEFINITIONS = (
378 | "DEBUG=1",
379 | "$(inherited)",
380 | );
381 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
382 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
383 | GCC_WARN_UNDECLARED_SELECTOR = YES;
384 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
385 | GCC_WARN_UNUSED_FUNCTION = YES;
386 | GCC_WARN_UNUSED_VARIABLE = YES;
387 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
388 | MTL_ENABLE_DEBUG_INFO = YES;
389 | ONLY_ACTIVE_ARCH = YES;
390 | SDKROOT = iphoneos;
391 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
392 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
393 | };
394 | name = Debug;
395 | };
396 | 8B33BD3C1FAEFE81002046F2 /* Release */ = {
397 | isa = XCBuildConfiguration;
398 | buildSettings = {
399 | ALWAYS_SEARCH_USER_PATHS = NO;
400 | CLANG_ANALYZER_NONNULL = YES;
401 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
402 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
403 | CLANG_CXX_LIBRARY = "libc++";
404 | CLANG_ENABLE_MODULES = YES;
405 | CLANG_ENABLE_OBJC_ARC = YES;
406 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
407 | CLANG_WARN_BOOL_CONVERSION = YES;
408 | CLANG_WARN_COMMA = YES;
409 | CLANG_WARN_CONSTANT_CONVERSION = YES;
410 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
411 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
412 | CLANG_WARN_EMPTY_BODY = YES;
413 | CLANG_WARN_ENUM_CONVERSION = YES;
414 | CLANG_WARN_INFINITE_RECURSION = YES;
415 | CLANG_WARN_INT_CONVERSION = YES;
416 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
417 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
418 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
419 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
420 | CLANG_WARN_STRICT_PROTOTYPES = YES;
421 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
422 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
423 | CLANG_WARN_UNREACHABLE_CODE = YES;
424 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
425 | CODE_SIGN_IDENTITY = "iPhone Developer";
426 | COPY_PHASE_STRIP = NO;
427 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
428 | ENABLE_NS_ASSERTIONS = NO;
429 | ENABLE_STRICT_OBJC_MSGSEND = YES;
430 | GCC_C_LANGUAGE_STANDARD = gnu11;
431 | GCC_NO_COMMON_BLOCKS = YES;
432 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
433 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
434 | GCC_WARN_UNDECLARED_SELECTOR = YES;
435 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
436 | GCC_WARN_UNUSED_FUNCTION = YES;
437 | GCC_WARN_UNUSED_VARIABLE = YES;
438 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
439 | MTL_ENABLE_DEBUG_INFO = NO;
440 | SDKROOT = iphoneos;
441 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
442 | VALIDATE_PRODUCT = YES;
443 | };
444 | name = Release;
445 | };
446 | 8B33BD3E1FAEFE81002046F2 /* Debug */ = {
447 | isa = XCBuildConfiguration;
448 | buildSettings = {
449 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
450 | CODE_SIGN_STYLE = Manual;
451 | DEVELOPMENT_TEAM = "";
452 | INFOPLIST_FILE = VPCollectionViewLayoutExample/Info.plist;
453 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
454 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
455 | PRODUCT_BUNDLE_IDENTIFIER = VPM.VPCollectionViewLayoutExample;
456 | PRODUCT_NAME = "$(TARGET_NAME)";
457 | PROVISIONING_PROFILE_SPECIFIER = "";
458 | SWIFT_VERSION = 4.0;
459 | TARGETED_DEVICE_FAMILY = "1,2";
460 | };
461 | name = Debug;
462 | };
463 | 8B33BD3F1FAEFE81002046F2 /* Release */ = {
464 | isa = XCBuildConfiguration;
465 | buildSettings = {
466 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
467 | CODE_SIGN_STYLE = Manual;
468 | DEVELOPMENT_TEAM = "";
469 | INFOPLIST_FILE = VPCollectionViewLayoutExample/Info.plist;
470 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
471 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
472 | PRODUCT_BUNDLE_IDENTIFIER = VPM.VPCollectionViewLayoutExample;
473 | PRODUCT_NAME = "$(TARGET_NAME)";
474 | PROVISIONING_PROFILE_SPECIFIER = "";
475 | SWIFT_VERSION = 4.0;
476 | TARGETED_DEVICE_FAMILY = "1,2";
477 | };
478 | name = Release;
479 | };
480 | 8B33BD411FAEFE81002046F2 /* Debug */ = {
481 | isa = XCBuildConfiguration;
482 | buildSettings = {
483 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
484 | BUNDLE_LOADER = "$(TEST_HOST)";
485 | CODE_SIGN_STYLE = Automatic;
486 | INFOPLIST_FILE = VPCollectionViewLayoutExampleTests/Info.plist;
487 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
488 | PRODUCT_BUNDLE_IDENTIFIER = VPM.VPCollectionViewLayoutExampleTests;
489 | PRODUCT_NAME = "$(TARGET_NAME)";
490 | SWIFT_VERSION = 4.0;
491 | TARGETED_DEVICE_FAMILY = "1,2";
492 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VPCollectionViewLayoutExample.app/VPCollectionViewLayoutExample";
493 | };
494 | name = Debug;
495 | };
496 | 8B33BD421FAEFE81002046F2 /* Release */ = {
497 | isa = XCBuildConfiguration;
498 | buildSettings = {
499 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
500 | BUNDLE_LOADER = "$(TEST_HOST)";
501 | CODE_SIGN_STYLE = Automatic;
502 | INFOPLIST_FILE = VPCollectionViewLayoutExampleTests/Info.plist;
503 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
504 | PRODUCT_BUNDLE_IDENTIFIER = VPM.VPCollectionViewLayoutExampleTests;
505 | PRODUCT_NAME = "$(TARGET_NAME)";
506 | SWIFT_VERSION = 4.0;
507 | TARGETED_DEVICE_FAMILY = "1,2";
508 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VPCollectionViewLayoutExample.app/VPCollectionViewLayoutExample";
509 | };
510 | name = Release;
511 | };
512 | 8B33BD441FAEFE81002046F2 /* Debug */ = {
513 | isa = XCBuildConfiguration;
514 | buildSettings = {
515 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
516 | CODE_SIGN_STYLE = Automatic;
517 | INFOPLIST_FILE = VPCollectionViewLayoutExampleUITests/Info.plist;
518 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
519 | PRODUCT_BUNDLE_IDENTIFIER = VPM.VPCollectionViewLayoutExampleUITests;
520 | PRODUCT_NAME = "$(TARGET_NAME)";
521 | SWIFT_VERSION = 4.0;
522 | TARGETED_DEVICE_FAMILY = "1,2";
523 | TEST_TARGET_NAME = VPCollectionViewLayoutExample;
524 | };
525 | name = Debug;
526 | };
527 | 8B33BD451FAEFE81002046F2 /* Release */ = {
528 | isa = XCBuildConfiguration;
529 | buildSettings = {
530 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
531 | CODE_SIGN_STYLE = Automatic;
532 | INFOPLIST_FILE = VPCollectionViewLayoutExampleUITests/Info.plist;
533 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
534 | PRODUCT_BUNDLE_IDENTIFIER = VPM.VPCollectionViewLayoutExampleUITests;
535 | PRODUCT_NAME = "$(TARGET_NAME)";
536 | SWIFT_VERSION = 4.0;
537 | TARGETED_DEVICE_FAMILY = "1,2";
538 | TEST_TARGET_NAME = VPCollectionViewLayoutExample;
539 | };
540 | name = Release;
541 | };
542 | /* End XCBuildConfiguration section */
543 |
544 | /* Begin XCConfigurationList section */
545 | 8B33BD101FAEFE81002046F2 /* Build configuration list for PBXProject "VPCollectionViewLayoutExample" */ = {
546 | isa = XCConfigurationList;
547 | buildConfigurations = (
548 | 8B33BD3B1FAEFE81002046F2 /* Debug */,
549 | 8B33BD3C1FAEFE81002046F2 /* Release */,
550 | );
551 | defaultConfigurationIsVisible = 0;
552 | defaultConfigurationName = Release;
553 | };
554 | 8B33BD3D1FAEFE81002046F2 /* Build configuration list for PBXNativeTarget "VPCollectionViewLayoutExample" */ = {
555 | isa = XCConfigurationList;
556 | buildConfigurations = (
557 | 8B33BD3E1FAEFE81002046F2 /* Debug */,
558 | 8B33BD3F1FAEFE81002046F2 /* Release */,
559 | );
560 | defaultConfigurationIsVisible = 0;
561 | defaultConfigurationName = Release;
562 | };
563 | 8B33BD401FAEFE81002046F2 /* Build configuration list for PBXNativeTarget "VPCollectionViewLayoutExampleTests" */ = {
564 | isa = XCConfigurationList;
565 | buildConfigurations = (
566 | 8B33BD411FAEFE81002046F2 /* Debug */,
567 | 8B33BD421FAEFE81002046F2 /* Release */,
568 | );
569 | defaultConfigurationIsVisible = 0;
570 | defaultConfigurationName = Release;
571 | };
572 | 8B33BD431FAEFE81002046F2 /* Build configuration list for PBXNativeTarget "VPCollectionViewLayoutExampleUITests" */ = {
573 | isa = XCConfigurationList;
574 | buildConfigurations = (
575 | 8B33BD441FAEFE81002046F2 /* Debug */,
576 | 8B33BD451FAEFE81002046F2 /* Release */,
577 | );
578 | defaultConfigurationIsVisible = 0;
579 | defaultConfigurationName = Release;
580 | };
581 | /* End XCConfigurationList section */
582 | };
583 | rootObject = 8B33BD0D1FAEFE81002046F2 /* Project object */;
584 | }
585 |
--------------------------------------------------------------------------------