├── .gitignore
├── LICENSE
├── README.md
├── SquareFlowLayout.podspec
└── SquareFlowLayout
├── Example
└── SquareFlowLayout
│ ├── Podfile
│ ├── Podfile.lock
│ ├── SquareFlowLayout
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── ImageLoader.swift
│ ├── Info.plist
│ ├── PhotoCollectionViewCell.swift
│ ├── PhotoCollectionViewCell.xib
│ └── ViewController.swift
│ ├── SquareFlowLayoutExample.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcuserdata
│ │ │ └── taraschernyshenko.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ └── taraschernyshenko.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── SquareFlowLayoutExample.xcworkspace
│ └── contents.xcworkspacedata
├── Screenshots
├── SquareFlowLayout-1.png
├── SquareFlowLayout-2.png
├── SquareFlowLayout-3.png
├── SquareFlowLayout-4.png
└── logo.png
└── Source
└── Classes
└── SquareFlowLayout.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcodeproj/xcuserdata/
2 | SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcworkspace/xcshareddata/
3 | SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcworkspace/xcuserdata/
4 | SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcodeproj/project.xcworkspace/
5 | SquareFlowLayout/Example/SquareFlowLayout/Pods/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Taras Chernyshenko
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SquareFlowLayout
2 | 
3 | 
4 | [](http://makeapullrequest.com)
5 |
6 |
7 |
8 | Makes your `UICollectionView` to looks like Instagram explore has never been so easy before. `SquareFlowLayout` provide dynamic layout generation by defining which IndexPath should be expanded.
9 |
10 | ## Installation
11 |
12 | #### CocoaPods
13 |
14 | `pod 'SquareFlowLayout'`
15 |
16 | #### Manually
17 |
18 | 1. Download and drop ```Classes``` folder into your project.
19 | 2. Congratulations!
20 |
21 | ## Usage
22 |
23 | 1. Set `SquareFlowLayout` to your UICollectionView and set it `flowDelegate`
24 |
25 | ```
26 | let flowLayout = SquareFlowLayout()
27 | flowLayout.flowDelegate = self
28 | self.collectionView.collectionViewLayout = flowLayout
29 | ```
30 |
31 | 2. Make your class conform to `SquareFlowLayoutDelegate`
32 | 3. Use delegate method to decide which cell should be pinned
33 | ```
34 | extension ViewController: SquareFlowLayoutDelegate {
35 | func shouldExpandItem(at indexPath: IndexPath) -> Bool {
36 | return self.layoutValues[indexPath.row] == .expanded
37 | }
38 | }
39 | ```
40 | 4. Look into example project for more info
41 |
42 |
43 |
44 |
45 |
46 | ## Contributing to this project
47 |
48 | If you like this tool, show your support by tell me how do u use it.
49 |
50 | ## License
51 |
52 | This code is distributed under the terms and conditions of the [MIT license](LICENSE).
53 |
--------------------------------------------------------------------------------
/SquareFlowLayout.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'SquareFlowLayout'
3 | s.version = '0.0.1'
4 | s.summary = 'A lightweight implementation of Instagram like UICollectionViewFlowLayout'
5 |
6 | s.description = <<-DESC
7 | Making more easy to implement dynamic flow layout similar for Instragram explore screen
8 | DESC
9 |
10 | s.homepage = 'https://github.com/ChernyshenkoTaras/SquareFlowLayout'
11 | s.license = { :type => 'MIT', :file => 'LICENSE' }
12 | s.author = { 'Taras Chernyshenko' => 'taras.chernyshenko@gmail.com' }
13 | s.source = { :git => 'https://github.com/ChernyshenkoTaras/SquareFlowLayout.git', :tag => s.version.to_s }
14 | s.social_media_url = 'https://twitter.com/@t_chernyshenko'
15 |
16 | s.ios.deployment_target = '9.0'
17 | s.swift_version = '4.2'
18 | s.source_files = 'SquareFlowLayout/Source/Classes/**/*'
19 | end
20 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 | platform :ios, '9.0'
3 | use_frameworks!
4 |
5 | target 'SquareFlowLayoutExample' do
6 | pod 'SquareFlowLayout', :path => '../../../'
7 | end
8 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - SquareFlowLayout (0.0.1)
3 |
4 | DEPENDENCIES:
5 | - SquareFlowLayout (from `../../../`)
6 |
7 | EXTERNAL SOURCES:
8 | SquareFlowLayout:
9 | :path: "../../../"
10 |
11 | SPEC CHECKSUMS:
12 | SquareFlowLayout: def664bf2b05195473349548faf1cf89d0956502
13 |
14 | PODFILE CHECKSUM: f0fe7b27d3442fdc761fabfd9bd6951bf070f9f9
15 |
16 | COCOAPODS: 1.9.1
17 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SquareFlowLayout
4 | //
5 | // Created by Taras Chernyshenko on 11/11/18.
6 | // Copyright © 2018 Taras Chernyshenko. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 | var window: UIWindow?
14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
15 | // Override point for customization after application launch.
16 | return true
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/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 | }
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/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 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/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 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/ImageLoader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageLoader.swift
3 | // SquareFlowLayout
4 | //
5 | // Created by Taras Chernyshenko on 11/11/18.
6 | // Copyright © 2018 Taras Chernyshenko. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class ImageLoader {
12 | private static let loadingQueue = DispatchQueue(label: "image.loading.queue")
13 | static func load(from url: URL, completion: @escaping (UIImage?) -> ()) {
14 | self.loadingQueue.async {
15 | do {
16 | let cache = ImageCache(path: url.lastPathComponent)
17 | var data: Data
18 | if cache.isExist {
19 | data = try Data(contentsOf: cache.cacheURL)
20 | } else {
21 | data = try Data(contentsOf: url)
22 | cache.save(data)
23 | }
24 | DispatchQueue.main.async {
25 | completion(UIImage(data: data))
26 | }
27 | } catch {
28 | DispatchQueue.main.async {
29 | completion(nil)
30 | }
31 | }
32 | }
33 | }
34 | }
35 |
36 | final class ImageCache {
37 | public enum MimeType: String {
38 | case jpg
39 | }
40 | private let path: String
41 | private let mimeType: MimeType
42 | private let fileManager = FileManager.default
43 |
44 | public lazy var cacheURL: URL = {
45 | let videoDirectory = self.getCacheDirectoryPath().appendingPathComponent("images")
46 | if !self.fileManager.fileExists(atPath: videoDirectory.path) {
47 | do {
48 | try self.fileManager.createDirectory(at: videoDirectory, withIntermediateDirectories: true, attributes: nil)
49 | } catch {
50 | assertionFailure(error.localizedDescription)
51 | }
52 | }
53 | return videoDirectory.appendingPathComponent("\(self.path).\(self.mimeType.rawValue)")
54 | }()
55 |
56 | init(path: String, mimeType: MimeType = .jpg) {
57 | self.path = path
58 | self.mimeType = mimeType
59 | }
60 |
61 | public var isExist: Bool {
62 | return self.fileManager.fileExists(atPath: self.cacheURL.path)
63 | }
64 |
65 | public func save(_ data: Data) {
66 | self.fileManager.createFile(atPath: self.cacheURL.path, contents: data)
67 | }
68 |
69 | private func getCacheDirectoryPath() -> URL {
70 | let fm = FileManager.default
71 | let folderName = "SquareFlowLayoutCache"
72 | let cacheFolderPath = fm.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent(folderName)
73 | return cacheFolderPath
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/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 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/PhotoCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PhotoCollectionViewCell.swift
3 | // SquareFlowLayout
4 | //
5 | // Created by Taras Chernyshenko on 11/11/18.
6 | // Copyright © 2018 Taras Chernyshenko. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class PhotoCollectionViewCell: UICollectionViewCell {
12 | @IBOutlet weak var imageView: UIImageView!
13 | }
14 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/PhotoCollectionViewCell.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 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayout/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SquareFlowLayout
4 | //
5 | // Created by Taras Chernyshenko on 11/11/18.
6 | // Copyright © 2018 Taras Chernyshenko. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SquareFlowLayout
11 |
12 | class ViewController: UIViewController {
13 | enum CellType {
14 | case normal
15 | case expanded
16 | }
17 | @IBOutlet private var collectionView: UICollectionView!
18 | private var photos: [Int : UIImage] = [:]
19 |
20 | private let layoutValues: [CellType] = [
21 | .expanded, .normal, .normal,
22 | .normal, .normal, .normal,
23 | .normal, .normal, .normal,
24 | .normal, .expanded, .normal,
25 | .expanded, .normal, .normal,
26 | .normal, .expanded, .normal,
27 | .normal, .normal, .normal,
28 | .normal, .normal, .expanded,
29 | .normal, .normal, .normal,
30 | .normal, .expanded, .normal,
31 | .normal, .normal, .normal,
32 | .expanded, .normal, .normal,
33 | .normal, .normal, .normal,
34 | .normal, .expanded, .normal,
35 | .normal, .normal, .normal,
36 | .normal, .normal, .normal,
37 | .expanded, .normal, .normal,
38 | .normal, .normal, .normal,
39 | .normal, .normal, .expanded,
40 | .normal, .expanded, .normal,
41 | .normal, .normal, .normal,
42 | .normal, .normal, .normal,
43 | .expanded, .normal, .normal,
44 | .normal, .expanded, .normal,
45 | .normal, .normal, .normal,
46 | .normal, .normal, .expanded,
47 | .expanded, .normal, .normal
48 | ]
49 | override func viewDidLoad() {
50 | super.viewDidLoad()
51 | self.collectionView.dataSource = self
52 | let flowLayout = SquareFlowLayout()
53 | flowLayout.flowDelegate = self
54 | self.collectionView.collectionViewLayout = flowLayout
55 |
56 | self.collectionView.register(UINib(nibName: "PhotoCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "PhotoCollectionViewCell")
57 |
58 | for i in 0.. URL {
77 | return URL(string: "https://randomfox.ca/images/\(index).jpg")!
78 | }
79 | }
80 |
81 | extension ViewController: UICollectionViewDataSource {
82 | func collectionView(_ collectionView: UICollectionView,
83 | numberOfItemsInSection section: Int) -> Int {
84 | return self.photos.keys.count
85 | }
86 |
87 | func collectionView(_ collectionView: UICollectionView,
88 | cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
89 | guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCollectionViewCell", for: indexPath) as? PhotoCollectionViewCell else {
90 | return UICollectionViewCell()
91 | }
92 | cell.imageView.image = self.photos[indexPath.row]
93 | return cell
94 | }
95 | }
96 |
97 | extension ViewController: SquareFlowLayoutDelegate {
98 | func shouldExpandItem(at indexPath: IndexPath) -> Bool {
99 | return self.layoutValues[indexPath.row] == .expanded
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 212B17B81AC3B5B094B0E73E /* Pods_SquareFlowLayoutExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8ECED110CFFA282DD1644690 /* Pods_SquareFlowLayoutExample.framework */; };
11 | 2F59A97B21982C3600CC6440 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F59A97A21982C3600CC6440 /* AppDelegate.swift */; };
12 | 2F59A97D21982C3600CC6440 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F59A97C21982C3600CC6440 /* ViewController.swift */; };
13 | 2F59A98021982C3600CC6440 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2F59A97E21982C3600CC6440 /* Main.storyboard */; };
14 | 2F59A98221982C3700CC6440 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2F59A98121982C3700CC6440 /* Assets.xcassets */; };
15 | 2F59A98521982C3700CC6440 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2F59A98321982C3700CC6440 /* LaunchScreen.storyboard */; };
16 | 2F59A98F21982F2000CC6440 /* ImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F59A98C21982F2000CC6440 /* ImageLoader.swift */; };
17 | 2F59A99021982F2000CC6440 /* PhotoCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F59A98D21982F2000CC6440 /* PhotoCollectionViewCell.swift */; };
18 | 2F59A99121982F2000CC6440 /* PhotoCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2F59A98E21982F2000CC6440 /* PhotoCollectionViewCell.xib */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXFileReference section */
22 | 0814CE802EF6F2101C007C5C /* Pods-SquareFlowLayoutExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SquareFlowLayoutExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-SquareFlowLayoutExample/Pods-SquareFlowLayoutExample.release.xcconfig"; sourceTree = ""; };
23 | 2F59A97721982C3600CC6440 /* SquareFlowLayoutExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SquareFlowLayoutExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
24 | 2F59A97A21982C3600CC6440 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
25 | 2F59A97C21982C3600CC6440 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
26 | 2F59A97F21982C3600CC6440 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
27 | 2F59A98121982C3700CC6440 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
28 | 2F59A98421982C3700CC6440 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
29 | 2F59A98621982C3700CC6440 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | 2F59A98C21982F2000CC6440 /* ImageLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageLoader.swift; sourceTree = ""; };
31 | 2F59A98D21982F2000CC6440 /* PhotoCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoCollectionViewCell.swift; sourceTree = ""; };
32 | 2F59A98E21982F2000CC6440 /* PhotoCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PhotoCollectionViewCell.xib; sourceTree = ""; };
33 | 2FDE850517458678D9ADFA0F /* Pods-SquareFlowLayoutExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SquareFlowLayoutExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SquareFlowLayoutExample/Pods-SquareFlowLayoutExample.debug.xcconfig"; sourceTree = ""; };
34 | 49AD69F7FAFD4DD735BECE1A /* Pods_SquareFlowLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SquareFlowLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; };
35 | 8ECED110CFFA282DD1644690 /* Pods_SquareFlowLayoutExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SquareFlowLayoutExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
36 | 96D2552D947BBDC5AC748AA1 /* Pods-SquareFlowLayout.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SquareFlowLayout.release.xcconfig"; path = "Pods/Target Support Files/Pods-SquareFlowLayout/Pods-SquareFlowLayout.release.xcconfig"; sourceTree = ""; };
37 | BBD179C975A01C98D27BAB3B /* Pods-SquareFlowLayout.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SquareFlowLayout.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SquareFlowLayout/Pods-SquareFlowLayout.debug.xcconfig"; sourceTree = ""; };
38 | /* End PBXFileReference section */
39 |
40 | /* Begin PBXFrameworksBuildPhase section */
41 | 2F59A97421982C3600CC6440 /* Frameworks */ = {
42 | isa = PBXFrameworksBuildPhase;
43 | buildActionMask = 2147483647;
44 | files = (
45 | 212B17B81AC3B5B094B0E73E /* Pods_SquareFlowLayoutExample.framework in Frameworks */,
46 | );
47 | runOnlyForDeploymentPostprocessing = 0;
48 | };
49 | /* End PBXFrameworksBuildPhase section */
50 |
51 | /* Begin PBXGroup section */
52 | 2F59A96E21982C3500CC6440 = {
53 | isa = PBXGroup;
54 | children = (
55 | 2F59A97921982C3600CC6440 /* SquareFlowLayout */,
56 | 2F59A97821982C3600CC6440 /* Products */,
57 | 41D470923AD4FA15710C9FFF /* Pods */,
58 | E3DE199B3EAB6EC47FCA6520 /* Frameworks */,
59 | );
60 | sourceTree = "";
61 | };
62 | 2F59A97821982C3600CC6440 /* Products */ = {
63 | isa = PBXGroup;
64 | children = (
65 | 2F59A97721982C3600CC6440 /* SquareFlowLayoutExample.app */,
66 | );
67 | name = Products;
68 | sourceTree = "";
69 | };
70 | 2F59A97921982C3600CC6440 /* SquareFlowLayout */ = {
71 | isa = PBXGroup;
72 | children = (
73 | 2F59A98C21982F2000CC6440 /* ImageLoader.swift */,
74 | 2F59A98D21982F2000CC6440 /* PhotoCollectionViewCell.swift */,
75 | 2F59A98E21982F2000CC6440 /* PhotoCollectionViewCell.xib */,
76 | 2F59A97A21982C3600CC6440 /* AppDelegate.swift */,
77 | 2F59A97C21982C3600CC6440 /* ViewController.swift */,
78 | 2F59A97E21982C3600CC6440 /* Main.storyboard */,
79 | 2F59A98121982C3700CC6440 /* Assets.xcassets */,
80 | 2F59A98321982C3700CC6440 /* LaunchScreen.storyboard */,
81 | 2F59A98621982C3700CC6440 /* Info.plist */,
82 | );
83 | path = SquareFlowLayout;
84 | sourceTree = "";
85 | };
86 | 41D470923AD4FA15710C9FFF /* Pods */ = {
87 | isa = PBXGroup;
88 | children = (
89 | BBD179C975A01C98D27BAB3B /* Pods-SquareFlowLayout.debug.xcconfig */,
90 | 96D2552D947BBDC5AC748AA1 /* Pods-SquareFlowLayout.release.xcconfig */,
91 | 2FDE850517458678D9ADFA0F /* Pods-SquareFlowLayoutExample.debug.xcconfig */,
92 | 0814CE802EF6F2101C007C5C /* Pods-SquareFlowLayoutExample.release.xcconfig */,
93 | );
94 | name = Pods;
95 | sourceTree = "";
96 | };
97 | E3DE199B3EAB6EC47FCA6520 /* Frameworks */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 49AD69F7FAFD4DD735BECE1A /* Pods_SquareFlowLayout.framework */,
101 | 8ECED110CFFA282DD1644690 /* Pods_SquareFlowLayoutExample.framework */,
102 | );
103 | name = Frameworks;
104 | sourceTree = "";
105 | };
106 | /* End PBXGroup section */
107 |
108 | /* Begin PBXNativeTarget section */
109 | 2F59A97621982C3600CC6440 /* SquareFlowLayoutExample */ = {
110 | isa = PBXNativeTarget;
111 | buildConfigurationList = 2F59A98921982C3700CC6440 /* Build configuration list for PBXNativeTarget "SquareFlowLayoutExample" */;
112 | buildPhases = (
113 | 1DBF0BDEF5E7E149E99A0FEC /* [CP] Check Pods Manifest.lock */,
114 | 2F59A97321982C3600CC6440 /* Sources */,
115 | 2F59A97421982C3600CC6440 /* Frameworks */,
116 | 2F59A97521982C3600CC6440 /* Resources */,
117 | 285AC611995F5DD89BA83B63 /* [CP] Embed Pods Frameworks */,
118 | );
119 | buildRules = (
120 | );
121 | dependencies = (
122 | );
123 | name = SquareFlowLayoutExample;
124 | productName = SquareFlowLayout;
125 | productReference = 2F59A97721982C3600CC6440 /* SquareFlowLayoutExample.app */;
126 | productType = "com.apple.product-type.application";
127 | };
128 | /* End PBXNativeTarget section */
129 |
130 | /* Begin PBXProject section */
131 | 2F59A96F21982C3500CC6440 /* Project object */ = {
132 | isa = PBXProject;
133 | attributes = {
134 | LastSwiftUpdateCheck = 1000;
135 | LastUpgradeCheck = 1000;
136 | ORGANIZATIONNAME = "Taras Chernyshenko";
137 | TargetAttributes = {
138 | 2F59A97621982C3600CC6440 = {
139 | CreatedOnToolsVersion = 10.0;
140 | };
141 | };
142 | };
143 | buildConfigurationList = 2F59A97221982C3500CC6440 /* Build configuration list for PBXProject "SquareFlowLayoutExample" */;
144 | compatibilityVersion = "Xcode 9.3";
145 | developmentRegion = en;
146 | hasScannedForEncodings = 0;
147 | knownRegions = (
148 | en,
149 | Base,
150 | );
151 | mainGroup = 2F59A96E21982C3500CC6440;
152 | productRefGroup = 2F59A97821982C3600CC6440 /* Products */;
153 | projectDirPath = "";
154 | projectRoot = "";
155 | targets = (
156 | 2F59A97621982C3600CC6440 /* SquareFlowLayoutExample */,
157 | );
158 | };
159 | /* End PBXProject section */
160 |
161 | /* Begin PBXResourcesBuildPhase section */
162 | 2F59A97521982C3600CC6440 /* Resources */ = {
163 | isa = PBXResourcesBuildPhase;
164 | buildActionMask = 2147483647;
165 | files = (
166 | 2F59A98521982C3700CC6440 /* LaunchScreen.storyboard in Resources */,
167 | 2F59A99121982F2000CC6440 /* PhotoCollectionViewCell.xib in Resources */,
168 | 2F59A98221982C3700CC6440 /* Assets.xcassets in Resources */,
169 | 2F59A98021982C3600CC6440 /* Main.storyboard in Resources */,
170 | );
171 | runOnlyForDeploymentPostprocessing = 0;
172 | };
173 | /* End PBXResourcesBuildPhase section */
174 |
175 | /* Begin PBXShellScriptBuildPhase section */
176 | 1DBF0BDEF5E7E149E99A0FEC /* [CP] Check Pods Manifest.lock */ = {
177 | isa = PBXShellScriptBuildPhase;
178 | buildActionMask = 2147483647;
179 | files = (
180 | );
181 | inputPaths = (
182 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
183 | "${PODS_ROOT}/Manifest.lock",
184 | );
185 | name = "[CP] Check Pods Manifest.lock";
186 | outputPaths = (
187 | "$(DERIVED_FILE_DIR)/Pods-SquareFlowLayoutExample-checkManifestLockResult.txt",
188 | );
189 | runOnlyForDeploymentPostprocessing = 0;
190 | shellPath = /bin/sh;
191 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
192 | showEnvVarsInLog = 0;
193 | };
194 | 285AC611995F5DD89BA83B63 /* [CP] Embed Pods Frameworks */ = {
195 | isa = PBXShellScriptBuildPhase;
196 | buildActionMask = 2147483647;
197 | files = (
198 | );
199 | inputFileListPaths = (
200 | "${PODS_ROOT}/Target Support Files/Pods-SquareFlowLayoutExample/Pods-SquareFlowLayoutExample-frameworks-${CONFIGURATION}-input-files.xcfilelist",
201 | );
202 | name = "[CP] Embed Pods Frameworks";
203 | outputFileListPaths = (
204 | "${PODS_ROOT}/Target Support Files/Pods-SquareFlowLayoutExample/Pods-SquareFlowLayoutExample-frameworks-${CONFIGURATION}-output-files.xcfilelist",
205 | );
206 | runOnlyForDeploymentPostprocessing = 0;
207 | shellPath = /bin/sh;
208 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SquareFlowLayoutExample/Pods-SquareFlowLayoutExample-frameworks.sh\"\n";
209 | showEnvVarsInLog = 0;
210 | };
211 | /* End PBXShellScriptBuildPhase section */
212 |
213 | /* Begin PBXSourcesBuildPhase section */
214 | 2F59A97321982C3600CC6440 /* Sources */ = {
215 | isa = PBXSourcesBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | 2F59A97D21982C3600CC6440 /* ViewController.swift in Sources */,
219 | 2F59A99021982F2000CC6440 /* PhotoCollectionViewCell.swift in Sources */,
220 | 2F59A97B21982C3600CC6440 /* AppDelegate.swift in Sources */,
221 | 2F59A98F21982F2000CC6440 /* ImageLoader.swift in Sources */,
222 | );
223 | runOnlyForDeploymentPostprocessing = 0;
224 | };
225 | /* End PBXSourcesBuildPhase section */
226 |
227 | /* Begin PBXVariantGroup section */
228 | 2F59A97E21982C3600CC6440 /* Main.storyboard */ = {
229 | isa = PBXVariantGroup;
230 | children = (
231 | 2F59A97F21982C3600CC6440 /* Base */,
232 | );
233 | name = Main.storyboard;
234 | sourceTree = "";
235 | };
236 | 2F59A98321982C3700CC6440 /* LaunchScreen.storyboard */ = {
237 | isa = PBXVariantGroup;
238 | children = (
239 | 2F59A98421982C3700CC6440 /* Base */,
240 | );
241 | name = LaunchScreen.storyboard;
242 | sourceTree = "";
243 | };
244 | /* End PBXVariantGroup section */
245 |
246 | /* Begin XCBuildConfiguration section */
247 | 2F59A98721982C3700CC6440 /* Debug */ = {
248 | isa = XCBuildConfiguration;
249 | buildSettings = {
250 | ALWAYS_SEARCH_USER_PATHS = NO;
251 | CLANG_ANALYZER_NONNULL = YES;
252 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
253 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
254 | CLANG_CXX_LIBRARY = "libc++";
255 | CLANG_ENABLE_MODULES = YES;
256 | CLANG_ENABLE_OBJC_ARC = YES;
257 | CLANG_ENABLE_OBJC_WEAK = YES;
258 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
259 | CLANG_WARN_BOOL_CONVERSION = YES;
260 | CLANG_WARN_COMMA = YES;
261 | CLANG_WARN_CONSTANT_CONVERSION = YES;
262 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
264 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
265 | CLANG_WARN_EMPTY_BODY = YES;
266 | CLANG_WARN_ENUM_CONVERSION = YES;
267 | CLANG_WARN_INFINITE_RECURSION = YES;
268 | CLANG_WARN_INT_CONVERSION = YES;
269 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
270 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
271 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
272 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
273 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
274 | CLANG_WARN_STRICT_PROTOTYPES = YES;
275 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
276 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
277 | CLANG_WARN_UNREACHABLE_CODE = YES;
278 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
279 | CODE_SIGN_IDENTITY = "iPhone Developer";
280 | COPY_PHASE_STRIP = NO;
281 | DEBUG_INFORMATION_FORMAT = dwarf;
282 | ENABLE_STRICT_OBJC_MSGSEND = YES;
283 | ENABLE_TESTABILITY = YES;
284 | GCC_C_LANGUAGE_STANDARD = gnu11;
285 | GCC_DYNAMIC_NO_PIC = NO;
286 | GCC_NO_COMMON_BLOCKS = YES;
287 | GCC_OPTIMIZATION_LEVEL = 0;
288 | GCC_PREPROCESSOR_DEFINITIONS = (
289 | "DEBUG=1",
290 | "$(inherited)",
291 | );
292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
294 | GCC_WARN_UNDECLARED_SELECTOR = YES;
295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
296 | GCC_WARN_UNUSED_FUNCTION = YES;
297 | GCC_WARN_UNUSED_VARIABLE = YES;
298 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
299 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
300 | MTL_FAST_MATH = YES;
301 | ONLY_ACTIVE_ARCH = YES;
302 | SDKROOT = iphoneos;
303 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
304 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
305 | };
306 | name = Debug;
307 | };
308 | 2F59A98821982C3700CC6440 /* Release */ = {
309 | isa = XCBuildConfiguration;
310 | buildSettings = {
311 | ALWAYS_SEARCH_USER_PATHS = NO;
312 | CLANG_ANALYZER_NONNULL = YES;
313 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
314 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
315 | CLANG_CXX_LIBRARY = "libc++";
316 | CLANG_ENABLE_MODULES = YES;
317 | CLANG_ENABLE_OBJC_ARC = YES;
318 | CLANG_ENABLE_OBJC_WEAK = YES;
319 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
320 | CLANG_WARN_BOOL_CONVERSION = YES;
321 | CLANG_WARN_COMMA = YES;
322 | CLANG_WARN_CONSTANT_CONVERSION = YES;
323 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
325 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
326 | CLANG_WARN_EMPTY_BODY = YES;
327 | CLANG_WARN_ENUM_CONVERSION = YES;
328 | CLANG_WARN_INFINITE_RECURSION = YES;
329 | CLANG_WARN_INT_CONVERSION = YES;
330 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
331 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
332 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
333 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
334 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
335 | CLANG_WARN_STRICT_PROTOTYPES = YES;
336 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
337 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
338 | CLANG_WARN_UNREACHABLE_CODE = YES;
339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
340 | CODE_SIGN_IDENTITY = "iPhone Developer";
341 | COPY_PHASE_STRIP = NO;
342 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
343 | ENABLE_NS_ASSERTIONS = NO;
344 | ENABLE_STRICT_OBJC_MSGSEND = YES;
345 | GCC_C_LANGUAGE_STANDARD = gnu11;
346 | GCC_NO_COMMON_BLOCKS = YES;
347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
349 | GCC_WARN_UNDECLARED_SELECTOR = YES;
350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
351 | GCC_WARN_UNUSED_FUNCTION = YES;
352 | GCC_WARN_UNUSED_VARIABLE = YES;
353 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
354 | MTL_ENABLE_DEBUG_INFO = NO;
355 | MTL_FAST_MATH = YES;
356 | SDKROOT = iphoneos;
357 | SWIFT_COMPILATION_MODE = wholemodule;
358 | SWIFT_OPTIMIZATION_LEVEL = "-O";
359 | VALIDATE_PRODUCT = YES;
360 | };
361 | name = Release;
362 | };
363 | 2F59A98A21982C3700CC6440 /* Debug */ = {
364 | isa = XCBuildConfiguration;
365 | baseConfigurationReference = 2FDE850517458678D9ADFA0F /* Pods-SquareFlowLayoutExample.debug.xcconfig */;
366 | buildSettings = {
367 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
368 | CODE_SIGN_STYLE = Automatic;
369 | DEVELOPMENT_TEAM = Z5G3WDJ23W;
370 | INFOPLIST_FILE = SquareFlowLayout/Info.plist;
371 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
372 | LD_RUNPATH_SEARCH_PATHS = (
373 | "$(inherited)",
374 | "@executable_path/Frameworks",
375 | );
376 | PRODUCT_BUNDLE_IDENTIFIER = com.chernyshenko.SquareFlowLayout;
377 | PRODUCT_NAME = "$(TARGET_NAME)";
378 | SWIFT_VERSION = 4.2;
379 | TARGETED_DEVICE_FAMILY = "1,2";
380 | };
381 | name = Debug;
382 | };
383 | 2F59A98B21982C3700CC6440 /* Release */ = {
384 | isa = XCBuildConfiguration;
385 | baseConfigurationReference = 0814CE802EF6F2101C007C5C /* Pods-SquareFlowLayoutExample.release.xcconfig */;
386 | buildSettings = {
387 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
388 | CODE_SIGN_STYLE = Automatic;
389 | DEVELOPMENT_TEAM = Z5G3WDJ23W;
390 | INFOPLIST_FILE = SquareFlowLayout/Info.plist;
391 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
392 | LD_RUNPATH_SEARCH_PATHS = (
393 | "$(inherited)",
394 | "@executable_path/Frameworks",
395 | );
396 | PRODUCT_BUNDLE_IDENTIFIER = com.chernyshenko.SquareFlowLayout;
397 | PRODUCT_NAME = "$(TARGET_NAME)";
398 | SWIFT_VERSION = 4.2;
399 | TARGETED_DEVICE_FAMILY = "1,2";
400 | };
401 | name = Release;
402 | };
403 | /* End XCBuildConfiguration section */
404 |
405 | /* Begin XCConfigurationList section */
406 | 2F59A97221982C3500CC6440 /* Build configuration list for PBXProject "SquareFlowLayoutExample" */ = {
407 | isa = XCConfigurationList;
408 | buildConfigurations = (
409 | 2F59A98721982C3700CC6440 /* Debug */,
410 | 2F59A98821982C3700CC6440 /* Release */,
411 | );
412 | defaultConfigurationIsVisible = 0;
413 | defaultConfigurationName = Release;
414 | };
415 | 2F59A98921982C3700CC6440 /* Build configuration list for PBXNativeTarget "SquareFlowLayoutExample" */ = {
416 | isa = XCConfigurationList;
417 | buildConfigurations = (
418 | 2F59A98A21982C3700CC6440 /* Debug */,
419 | 2F59A98B21982C3700CC6440 /* Release */,
420 | );
421 | defaultConfigurationIsVisible = 0;
422 | defaultConfigurationName = Release;
423 | };
424 | /* End XCConfigurationList section */
425 | };
426 | rootObject = 2F59A96F21982C3500CC6440 /* Project object */;
427 | }
428 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcodeproj/project.xcworkspace/xcuserdata/taraschernyshenko.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChernyshenkoTaras/SquareFlowLayout/97de46f1dbd370d84fa9e407c42ac4d13e7960e8/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcodeproj/project.xcworkspace/xcuserdata/taraschernyshenko.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcodeproj/xcuserdata/taraschernyshenko.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SquareFlowLayout.xcscheme
8 |
9 | orderHint
10 | 3
11 |
12 | SquareFlowLayoutExample.xcscheme
13 |
14 | orderHint
15 | 3
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Example/SquareFlowLayout/SquareFlowLayoutExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/SquareFlowLayout/Screenshots/SquareFlowLayout-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChernyshenkoTaras/SquareFlowLayout/97de46f1dbd370d84fa9e407c42ac4d13e7960e8/SquareFlowLayout/Screenshots/SquareFlowLayout-1.png
--------------------------------------------------------------------------------
/SquareFlowLayout/Screenshots/SquareFlowLayout-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChernyshenkoTaras/SquareFlowLayout/97de46f1dbd370d84fa9e407c42ac4d13e7960e8/SquareFlowLayout/Screenshots/SquareFlowLayout-2.png
--------------------------------------------------------------------------------
/SquareFlowLayout/Screenshots/SquareFlowLayout-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChernyshenkoTaras/SquareFlowLayout/97de46f1dbd370d84fa9e407c42ac4d13e7960e8/SquareFlowLayout/Screenshots/SquareFlowLayout-3.png
--------------------------------------------------------------------------------
/SquareFlowLayout/Screenshots/SquareFlowLayout-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChernyshenkoTaras/SquareFlowLayout/97de46f1dbd370d84fa9e407c42ac4d13e7960e8/SquareFlowLayout/Screenshots/SquareFlowLayout-4.png
--------------------------------------------------------------------------------
/SquareFlowLayout/Screenshots/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChernyshenkoTaras/SquareFlowLayout/97de46f1dbd370d84fa9e407c42ac4d13e7960e8/SquareFlowLayout/Screenshots/logo.png
--------------------------------------------------------------------------------
/SquareFlowLayout/Source/Classes/SquareFlowLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SquareFlowLayout.swift
3 | //
4 | // Created by Taras Chernyshenko on 11/11/18.
5 | // Copyright © 2018 Taras Chernyshenko. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | public protocol SquareFlowLayoutDelegate: class {
11 | func shouldExpandItem(at indexPath: IndexPath) -> Bool
12 | }
13 |
14 | public class SquareFlowLayout: UICollectionViewFlowLayout {
15 | public enum ExpandedPosition {
16 | case start
17 | case middle
18 | case end
19 | case none
20 |
21 | /// Calculate the expanded position of a layout chunk.
22 | /// eg. [true, false, false] -> .start, [false, false, false] -> .none
23 | /// - Parameter layoutChunk: An array with boolean values, which represent if the cell should be expanded.
24 | public static func of(layoutChunk: [Bool]) -> ExpandedPosition {
25 | if layoutChunk.count > 0 && layoutChunk[0] {
26 | return .start
27 | } else if layoutChunk.count > 1 && layoutChunk[1] {
28 | return .middle
29 | } else if layoutChunk.count > 2 && layoutChunk[2] {
30 | return .end
31 | }
32 | return .none
33 | }
34 | }
35 |
36 | private var cache: [IndexPath: UICollectionViewLayoutAttributes] = [:]
37 | private var contentHeight: CGFloat = 0
38 | @IBInspectable public var interSpacing: CGFloat = 1
39 | private var contentWidth: CGFloat {
40 | guard let collectionView = collectionView else {
41 | return 0
42 | }
43 | let insets = collectionView.contentInset
44 | return collectionView.bounds.width - (insets.left + insets.right)
45 | }
46 |
47 | private var contentInsets: UIEdgeInsets {
48 | return collectionView?.contentInset ?? UIEdgeInsets.zero
49 | }
50 |
51 | public weak var flowDelegate: SquareFlowLayoutDelegate?
52 |
53 | public override var collectionViewContentSize: CGSize {
54 | return CGSize(width: contentWidth, height: contentHeight)
55 | }
56 |
57 | public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
58 | var layoutAttributesArray = [UICollectionViewLayoutAttributes]()
59 | if cache.isEmpty {
60 | prepare()
61 | }
62 | for (_, layoutAttributes) in cache {
63 | if rect.intersects(layoutAttributes.frame) {
64 | layoutAttributesArray.append(layoutAttributes)
65 | }
66 | }
67 | return layoutAttributesArray
68 | }
69 |
70 | public override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
71 | return cache[indexPath]
72 | }
73 |
74 | public override func prepare() {
75 | guard let collectionView = self.collectionView, collectionView.numberOfSections > 0 else {
76 | return
77 | }
78 |
79 | cache.removeAll()
80 |
81 | let numberOfColumns = 3
82 | contentHeight = 0
83 | let itemWidth = (contentWidth - CGFloat(numberOfColumns - 1) * interSpacing) / CGFloat(numberOfColumns)
84 | let itemHeight = itemWidth
85 |
86 | let expandedWidth = itemWidth * 2 + interSpacing
87 | let expandedHeight = expandedWidth
88 |
89 | var xOffset: CGFloat = 0
90 | var yOffset: CGFloat = 0
91 |
92 | var index = 0
93 | var layoutValues: [Bool] = []
94 | for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
95 | layoutValues.append(flowDelegate?.shouldExpandItem(at: IndexPath(row: item, section: 0)) == true)
96 | }
97 | let chunkSize = 3
98 | let layouts = stride(from: 0, to: layoutValues.count, by: chunkSize).map {
99 | Array(layoutValues[$0 ..< Swift.min($0 + chunkSize, layoutValues.count)])
100 | }
101 |
102 | func add(rect: CGRect, at idx: Int, in layout: [Bool]) {
103 | if idx < layout.count {
104 | let indexPath = IndexPath(row: index, section: 0)
105 | let targetLayoutAttributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
106 | targetLayoutAttributes.frame = rect
107 | contentHeight = max(rect.maxY, contentHeight)
108 | cache[indexPath] = targetLayoutAttributes
109 | index = index + 1
110 | }
111 | }
112 |
113 | for layout in layouts {
114 | let expandedPosition = ExpandedPosition.of(layoutChunk: layout)
115 | switch expandedPosition {
116 | case .start:
117 | add(rect: CGRect(x: 0, y: yOffset, width: expandedWidth, height: expandedHeight), at: 0, in: layout)
118 | add(rect: CGRect(x: expandedWidth + interSpacing, y: yOffset, width: itemWidth, height: itemHeight), at: 1, in: layout)
119 | add(rect: CGRect(x: expandedWidth + interSpacing, y: yOffset + itemHeight + interSpacing, width: itemWidth, height: itemHeight), at: 2, in: layout)
120 | case .middle:
121 | add(rect: CGRect(x: 0, y: yOffset, width: itemWidth, height: itemHeight), at: 0, in: layout)
122 | add(rect: CGRect(x: itemWidth + interSpacing, y: yOffset, width: expandedWidth, height: expandedHeight), at: 1, in: layout)
123 | add(rect: CGRect(x: 0, y: yOffset + itemHeight + interSpacing, width: itemWidth, height: itemHeight), at: 2, in: layout)
124 | case .end:
125 | add(rect: CGRect(x: 0, y: yOffset, width: itemWidth, height: itemHeight), at: 0, in: layout)
126 | add(rect: CGRect(x: 0, y: yOffset + itemHeight + interSpacing, width: itemWidth, height: itemHeight), at: 1, in: layout)
127 | add(rect: CGRect(x: itemWidth + interSpacing, y: yOffset, width: expandedWidth, height: expandedHeight), at: 2, in: layout)
128 | case .none:
129 | for i in 0 ..< layout.count {
130 | add(rect: CGRect(x: xOffset, y: yOffset, width: itemWidth, height: itemHeight), at: i, in: layout)
131 | xOffset = xOffset + itemWidth + interSpacing
132 | }
133 | }
134 | xOffset = 0
135 | yOffset = yOffset + (expandedPosition == .none ? itemHeight : expandedHeight) + interSpacing
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------