A SwiftUI implementation of UICollectionView & UITableView. Here's some of its useful features:
- supports preloading and onAppear/onDisappear.
- supports cell selection, with automatic support for SwiftUI editing mode.
- supports autosizing of cells.
- supports the new UICollectionViewCompositionalLayout, and any other UICollectionViewLayout
- supports removing separators for ASTableView.
- supports directly using FetchedResults as a data source
Report Bug · Suggest a feature
ASCollectionView is a swift package.
- It can be imported into an app project using Xcode’s new Swift Packages option, which is located within the File menu.
- When asked, use this repository's url: https://github.com/apptekstudios/ASCollectionView
import ASCollectionView
import SwiftUI
struct SingleSectionExampleView: View {
@State var dataExample = (0 ..< 30).map { $0 }
var body: some View
{
ASCollectionView(data: dataExample, dataID: \.self) { item, _ in
Color.blue
.overlay(Text("\(item)"))
}
.layout {
.grid(layoutMode: .adaptive(withMinItemSize: 100),
itemSpacing: 5,
lineSpacing: 5,
itemSize: .absolute(50))
}
}
}
Below is an example of how to include a collection view with two sections (each with their own data source). For an extended example with a custom compositional layout see here. Or for more in-depth examples download the demo project included in this repo.
import SwiftUI
import ASCollectionView
struct ExampleView: View {
@State var dataExampleA = (0 ..< 21).map { $0 }
@State var dataExampleB = (0 ..< 15).map { "ITEM \($0)" }
var body: some View
{
ASCollectionView
{
ASCollectionViewSection(
id: 0,
data: dataExampleA,
dataID: \.self)
{ item, _ in
Color.blue
.overlay(
Text("\(item)")
)
}
ASCollectionViewSection(
id: 1,
data: dataExampleB,
dataID: \.self)
{ item, _ in
Color.green
.overlay(
Text("Complex layout - \(item)")
)
}
.sectionHeader
{
HStack
{
Text("Section header")
.padding()
Spacer()
}
.background(Color.yellow)
}
.sectionFooter
{
Text("This is a section footer!")
.padding()
}
}
.layout { sectionID in
switch sectionID {
case 0:
// Here we use one of the provided convenience layouts
return .grid(layoutMode: .adaptive(withMinItemSize: 100),
itemSpacing: 5,
lineSpacing: 5,
itemSize: .absolute(50))
default:
return ASCollectionLayoutSection { environment in
// ...
// You could return any custom NSCollectionLayoutSection here. For an example see this file: /readmeAssets/SampleUsage.swift
// ...
}
}
}
}
}
ASCollectionView has support for supplementary views. To add a supplementary view, use the sectionHeader
, sectionFooter
, or sectionSupplementary
modifiers on your ASCollectionViewSection.
sectionHeader
andsectionFooter
set the supplementary forUICollectionView.elementKindSectionHeader
andUICollectionView.elementKindSectionHeader
respectively.sectionSupplementary
lets you specify any supplementaryKind.
ASCollectionViewSection(...) { ... }
.sectionHeader
{
Text("Section header")
.background(Color.yellow)
}
.sectionFooter
{
Text("Section footer")
.background(Color.blue)
}
.sectionSupplementary(ofKind: "someOtherSupplementaryKindRequestedByYourLayout") {
Text("Section supplementary")
.background(Color.green)
}
A UICollectionViewLayout can layout decoration views that do not relate to the data (eg. a section background). These cannot be configured so you must provide a View struct that can be initialised using .init().
- To enforce this requirement, your view must conform to the
Decoration
protocol. The only requirement of this is an initialiser with no arguments. - You must register the view type with the layout.
- See the Reminders screen of the Demo app for a working example.
Declaring a swift view conforming to Decoration
:
struct GroupBackground: View, Decoration
{
let cornerRadius: CGFloat = 12
var body: some View
{
RoundedRectangle(cornerRadius: cornerRadius)
.fill(Color(.secondarySystemGroupedBackground))
}
}
Registering the decoration type with the layout (ASCollectionLayout):
var layout: ASCollectionLayout<Section>
{
ASCollectionLayout<Section>
{
// ... Here is an example of including a decoration in a compositional layout.
let sectionBackgroundDecoration = NSCollectionLayoutDecorationItem.background(elementKind: "groupBackground")
sectionBackgroundDecoration.contentInsets = section.contentInsets
section.decorationItems = [sectionBackgroundDecoration]
// ...
}
.decorationView(GroupBackground.self, forDecorationViewOfKind: "groupBackground") //REGISTER the decoration view type
- There is inbuilt support for the new UICollectionViewCompositionalLayout.
- You can define layout on a per-section basis, including the use of a switch statement if desired.
- Work in progress: There are some useful methods that allow for easy definition of list and grid-based layouts (including orthogonal grids).
Define layout for all sections:
ASCollectionView(...) { ... }
.layout {
ASCollectionLayoutSection { layoutEnvironment in
//Construct and return a NSCollectionLayoutSection here
}
}
Define layout per section:
ASCollectionView(...) { ... }
.layout { sectionID in
switch sectionID {
case .userSection:
return ASCollectionLayoutSection { layoutEnvironment in
//Construct and return a NSCollectionLayoutSection here
}
}
case .postSection:
return ASCollectionLayoutSection { layoutEnvironment in
//Construct and return a NSCollectionLayoutSection here
}
}
}
Use a custom UICollectionViewLayout:
ASCollectionView(...) { ... }
.layout {
let someCustomLayout = CustomUICollectionViewLayout()
someCustomLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
return someCustomLayout
}
- You can use an enum as your SectionID (rather than just an Int), this lets you easily determine the layout of each section.
- See the demo project for more in-depth usage examples.
- Please note that you should only use @State for transient visible state in collection view cells. Anything you want to persist long-term should be stored in your model.
See the open issues for a list of proposed features (and known issues).
Distributed under the MIT License. See LICENSE
for more information.