{"id":21437614,"url":"https://github.com/gabrieltheodoropoulos/gtcollectionviewkit","last_synced_at":"2025-03-16T23:41:48.684Z","repository":{"id":79559030,"uuid":"239004413","full_name":"gabrieltheodoropoulos/GTCollectionViewKit","owner":"gabrieltheodoropoulos","description":"A framework that introduces an alternative new way to use collection views in iOS projects!","archived":false,"fork":false,"pushed_at":"2020-02-13T07:49:10.000Z","size":775,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-23T09:43:37.780Z","etag":null,"topics":["class","framework","generics","ios","protocol","sizeclasses","swift","uicollectionview","xcframework","xcode"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gabrieltheodoropoulos.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-07T19:12:20.000Z","updated_at":"2020-02-15T18:33:13.000Z","dependencies_parsed_at":"2023-03-13T20:09:49.363Z","dependency_job_id":null,"html_url":"https://github.com/gabrieltheodoropoulos/GTCollectionViewKit","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieltheodoropoulos%2FGTCollectionViewKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieltheodoropoulos%2FGTCollectionViewKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieltheodoropoulos%2FGTCollectionViewKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gabrieltheodoropoulos%2FGTCollectionViewKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gabrieltheodoropoulos","download_url":"https://codeload.github.com/gabrieltheodoropoulos/GTCollectionViewKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243950792,"owners_count":20373664,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["class","framework","generics","ios","protocol","sizeclasses","swift","uicollectionview","xcframework","xcode"],"created_at":"2024-11-23T00:27:54.095Z","updated_at":"2025-03-16T23:41:48.663Z","avatar_url":"https://github.com/gabrieltheodoropoulos.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GTCollectionViewKit\n\n![Platform](https://img.shields.io/badge/Platform-iOS-lightgrey)\n![Language](https://img.shields.io/badge/Language-Swift-orange)\n![Version](https://img.shields.io/badge/Version-1.1.0-blue)\n\n#### Using collection views in iOS projects made easy!\n\n## What GTCollectionViewKit does?\n\n**GTCollectionViewKit** provides an alternative, yet simple and quite effective way to integrate collection views into your iOS projects. Its primary purpose is to *create a container view with a collection view embedded in it*, with the collection view configuration being possible through a variety of provided methods.\n\n## What GTCollectionViewKit is?\n\nGTCollectionViewKit is a **binary framework (.xcframework)** working in both devices and the simulator. It provides a public API through which is possible to use all available features. Find more about binary frameworks [here](https://developer.apple.com/videos/play/wwdc2019/416/).\n\n### Integrating GTCollectionViewKit\n\nTo use GTCollectionViewKit framework in your projects:\n\n* Download or clone this repository.\n* In Xcode, select your project in the Project navigator and go to *General* tab.\n* Drag and drop *GTCollectionViewKit.xcframework* into the *Frameworks, Libraries and Embedded Content* section.\n\n![Framework Integrated](https://gtiapps.com/misc/samples/gtcollectionviewkit/gtcollectionview_integrated.png)\n\nAdd the following `import` statement to each file where GTCollectionViewKit is going to be used:\n\n```swift\nimport GTCollectionViewKit\n```\n\n## GTCollectionViewKit API at a glance\n\nGTCollectionViewKit public API offers a number of classes and protocols:\n\n* `GTCollectionView`: The custom collection view implementation, a `UICollectionView` subclass.\n* `GTCollectionViewContainer`: The container view that has a `GTCollectionView` collection view embedded in it.\n* `GTCollectionViewCore`: A class with custom types that are used to specify the details of the collection view, such as the layout style, layout details, and more.\n* `GTCollectionViewApplicable`: A protocol to adopt on any view controller or view subclass that is about to use `GTCollectionViewContainer` instances.\n* `GTCollectionViewAdaptable`: Adopt this protocol in case you want to manually integrate and handle `GTCollectionView` in your views and not to use the `GTCollectionViewContainer` class.\n* `GTCollectionViewPresets`: A collection of custom types provided for convenience.\n* `GTTitleSubtitleImageCell`: A `UICollectionViewCell` subclass that can be used with NIB files. It provides IBOutlet properties for two labels and an image view.\n* `GTCollectionViewDatasource`: Custom types that keep and handle the data of the collection view datasource.\n\n*All classes, protocols, methods and properties are well documented. Use the Quick Help in Xcode to access documentation.*\n\n\n## The GTCollectionViewContainer container view\n\nThere are four methods to initialize a `GTCollectionViewContainer` container view and specify the style of the embedded collection view:\n\n```swift\ncreateGrid(withColumns:datasource:registerElements:layoutInfo:)\n// It creates a container view with a grid-based collection view.\n\ncreateList(withDatasource:registerElements:layoutInfo:)\n// It creates a container view with a list-based collection view.\n\ncreateCollection(withLayoutRules:datasource:registerElements:layoutInfo:)\n// It creates a container view with a collection view that supports different\n// layout styles for various combinations of horizontal and vertical size classes.\n\ncreateCollection(withTotalSections:itemsPerSection:layoutStyle:columns:registerElements:layoutInfo:)\n// It creates a collection view with the specified number of sections and items.\n// Use this method to create a GTCollectionViewContainer view only when you want\n// to use the collection view cells as placeholders for other content and there is not\n// a datasource to display data.\n```\n\nThe first three of them accept the collection view's datasource as a parameter value, as well as objects that describe the elements to register (cells, headers, footers) and the layout style of the collection view. For details see the documentation of the `GTCollectionViewCore.RegisterElement` and `GTCollectionViewCore.LayoutInfo` classes.\n\nThe third method above makes it possible to create a `GTCollectionViewContainer` view with a collection view that can have different styles depending on the specified size classes combination. For example, you can have list layout in compact vertical and regular horizontal size classes, and grid layout for regular vertical and any horizontal size classes.\n\n**Important #1**\n\nThe returned type of the first three methods above is `GTCollectionViewContainer\u003cT\u003e`, where T is the *type of the source data* that will be displayed on the collection view. When declaring container views as properties, then make sure to specify the datasource type as well. For example:\n\n```swift\n// Collection view's datasource is of Int type.\nvar cvContainer: GTCollectionViewContainer\u003cInt\u003e?\n\n// Collection view's datasource type is of MyType type.\nvar anotherContainer: GTCollectionViewContainer\u003cMyType\u003e?\n```\n\nThis requirement comes from the `GTCollectionView` definition (`GTCollectionView\u003cT\u003e`), which also requires the datasource type to be specified when initializing an object of it. Using generics that way makes it possible for GTCollectionViewKit to provide collection views that work with any type.\n\nThe only exception is when using the `createCollection(withTotalSections:itemsPerSection:layoutStyle:columns:registerElements:layoutInfo:)` method to initialize a `GTCollectionViewContainer` view. In this case the returned type is `GTCollectionViewContainer\u003cAny\u003e` by default.\n\n**Important #2**\n\nNote that the public provided methods allowing to configure the collection view should be **chained** right after the method that initializes a `GTCollectionViewContainer` view instance. See usage examples below.\n\n## The GTCollectionView\n\n`GTCollectionView` is a `UICollectionView` subclass. It's possible to use it directly in your views (or view controllers) but in that case it's also required to adopt the `GTCollectionViewAdaptable` protocol and implement all required methods. Those consist of the only way to configure and handle a `GTCollectionView`; no direct access to delegate or datasource methods is provided.\n\nWhen used through `GTCollectionViewContainer` views, collection view instances are accessible through the `collectionView` property of the `GTCollectionViewContainer` class.\n\nThe following is the definition of the initializer that you should use in case you integrate `GTCollectionView` directly:\n\n```swift\npublic init(withAdapter adapter: T, layoutStyle: GTCollectionViewCore.LayoutStyle, gridColumns: Int)\n```\n\n`adapter` is the class that integrates the `GTCollectionView` instance and adopts the `GTCollectionViewAdaptable` protocol, `layoutStyle` specifies whether data will be displayed as a list or a grid, and `gridColumns` specifies the number of columns in case of a grid layout style.\n\nOne method you might find interesting is the `setScrollDirection(scrollVertically:)` through which you can specify the scroll direction. By default, collection view scroll is set to vertical.\n\n## Usage examples\n\n*For detailed examples on how to use `GTCollectionViewKit` open the demo project in Xcode and navigate through all provided samples! Here is just a taste of it.*\n\n**Note:** In order to run the examples of the demo project, first add the GTCollectionViewKit framework to it following the steps described above in the *Integrating GTCollectionViewKit* part.\n\nFor starters, let's do some preparation:\n\n```swift\n// Declare the container view as a property:\nvar cvContainerView: GTCollectionViewContainer\u003cInt\u003e?\n\n// Define the sample datasource: An array of Int values.\nlet values: [Int] = [5, 10, 2, 37, 8, 12, 44, 12, 26, 4, 32, 19]\n```\n\nThe following creates a `GTCollectionViewContainer` view with a grid-based collection view. Notice that:\n\n1. The cell to register with the collection view along with a few details is specified at first. Resulting object is used right next.\n2. The container view is initialized. `datasource` parameter expects for a two-dimensional array.\n3. Collection view is being configured through the public methods of the `GTCollectionViewContainer` class. These methods must be **chained** right after the creation of the container view!\n4. The container view is added as a subview to another view.\n\n```swift\nfunc gridDemo() {\n    // Create a GTCollectionViewCore.RegisterElements object for registering\n    // MyCell custom cell with the collection view.\n    let registerElements = GTCollectionViewCore.RegisterElements(MyCell.self,\n                                                                 elementKind: .cell,\n                                                                 loadFromNib: true,\n                                                                 customNibName: nil)\n\n    // Initialize the container view.\n    cvContainerView = createGrid(withColumns: 2,\n                                 datasource: [values],\n                                 registerElements: registerElements,\n                                 layoutInfo: nil)\n\n        // Configure the cells.\n        .configureCell({ (cell, data, indexPath) -\u003e UICollectionViewCell in\n\n            // Configure the cell for each index path.\n            // cell is a UICollectionViewCell object, so casting to MyCell\n            // is necessary so we can access its custom properties.\n            guard let myCell = cell as? MyCell else {\n                return UICollectionViewCell()\n            }\n\n            // Populate the data matching to the current index path\n            // to the title label of the cell.\n            // Data is an Int number in this sample.\n            myCell.titleLabel?.text = \"\\(data)\"\n            return myCell\n\n        })\n\n        // Handle tap actions on cells.\n        .tapAction({ (indexPath) in\n            print(\"Tapped cell at\", indexPath)\n        })\n\n    // Add the container view as a subview to self view.\n    // The add(to:) method of the GTCollectionViewContainer class does the job.\n    // It adds the container view as a subview and sets up autolayout constraints.\n    cvContainerView?.add(to: self.view)\n}\n```\n\nHere's another example with a list-based collection view that also has a section header and defines layout details:\n\n```swift\nfunc listDemo_With_Header_And_LayoutInfo() {\n    // Specify a cell and a section header view to be registered\n    // with the collection view.\n    let registerElements = GTCollectionViewCore.RegisterElements()\n    registerElements.registerClass(MyCell.self, elementKind: .cell, loadFromNib: true, customNibName: nil)\n    registerElements.registerClass(MainHeaderView.self, elementKind: .header, loadFromNib: true, customNibName: nil)\n\n    // Specify layout details.\n    let layoutInfo = GTCollectionViewCore.LayoutInfo(withCellHeight: 120.0,\n                                                     columnSpacing: 0.0,\n                                                     rowSpacing: 24.0,\n                                                     sectionInset: .zero,\n                                                     makeSquare: false)\n\n    // Initialize the GTCollectionViewContainer view.\n    cvContainerView = createList(withDatasource: [values],\n                                 registerElements: registerElements,\n                                 layoutInfo: layoutInfo)\n\n        // Configure cells.\n        .configureCell({ (cell, data, indexPath) -\u003e UICollectionViewCell in\n            // Perform cell configuration...\n            return ... // configured cell\n        })\n\n        // Configure the header view.\n        .configureHeaderView({ (headerView, section) -\u003e UIView in\n            guard let view = headerView as? MyHeader else { return headerView }\n            view.label?.text = \"This is the Header!\"\n            return view\n        })\n\n        // Specify the header height.\n        .setHeaderHeight({ (section) -\u003e CGFloat in\n            return 180.0\n        })\n\n\n    // Add the container view as a subview to self view.\n    cvContainerView?.add(to: self.view)\n}\n```\n\nFinally, one last example that specifies different layout for different size class combinations:\n\n```swift\nfunc demo_Using_Size_Classes() {\n    // Specify the cell to register with the collection view.\n    let registerElements = GTCollectionViewCore.RegisterElements(MyCell.self, elementKind: .cell, loadFromNib: true, customNibName: nil)\n\n    // Specify layout rules (see GTCollectionViewCore.LayoutRule class) for various\n    // size class combinations right below.\n\n    // Rule #1:\n    // Use the list layout style when the horizontal size class is Compact.\n    // Passing nil to vertical size class will apply the rule to both Compact and Regular\n    // vertical size classes.\n    let CxAny = GTCollectionViewCore.LayoutRule(whenHorizontalSizeClassIs: .compact, andVerticalSizeClassIs: nil, applyLayoutStyle: .list, withColumns: 0)\n\n    // Rule #2:\n    // Use the grid layout style with 2 columns in Regular horizontal size class\n    // and Compact vertical size class.\n    let RxC = GTCollectionViewCore.LayoutRule(whenHorizontalSizeClassIs: .regular, andVerticalSizeClassIs: .compact, applyLayoutStyle: .grid, withColumns: 2)\n\n    // Rule #3:\n    // Use the grid layout style with 3 columns in Regular horizontal size class\n    // and Regular vertical size class.\n    let RxR = GTCollectionViewCore.LayoutRule(whenHorizontalSizeClassIs: .regular, andVerticalSizeClassIs: .regular, applyLayoutStyle: .grid, withColumns: 3)\n\n\n    // Create the container view with the collection view using the\n    // layout rules specified right above.\n    cvContainerView = createCollection(withLayoutRules: [CxAny, RxC, RxR],\n                                       datasource: [values],\n                                       registerElements: registerElements,\n                                       layoutInfo: nil)\n\n        .configureCell({ (cell, data, indexPath) -\u003e UICollectionViewCell in\n            // ... perform cell configuration\n        })\n\n\n    cvContainerView?.add(to: self.view)\n}\n```\n\n## Other\n\n* When reloading the collection view of a `GTCollectionViewContainer` view to display new data, use the `reload(withDatasource:)` method providing the updated datasource to be used with the collection view.\n* To get the full datasource provided in the collection view, use the `getDatasource()` of the `GTCollectionViewContainer` view instance. To get the data matching to a specific index path, use `getData(at:)`.\n\n## Legal statement \u0026 Copyright notice\n\nYou are allowed to use GTCollectionViewKit framework in both personal and commercial projects, and to extend it whenever that's possible. You are *not* allowed to sell it and claim ownership.\n\n**Copyright © 2020 Gabriel Theodoropoulos**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgabrieltheodoropoulos%2Fgtcollectionviewkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgabrieltheodoropoulos%2Fgtcollectionviewkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgabrieltheodoropoulos%2Fgtcollectionviewkit/lists"}