2️⃣UICollectionView Setup
Fall 2023 | Vin Bui
Create a Custom UICollectionViewCell
Creating a UICollectionViewCell is very similar to creating a UITableViewCell. However, there are just minor syntax changes. Follow these steps:
Our custom class needs to be a subclass of
UICollectionViewCellclass CustomCollectionViewCell: UICollectionViewCell { }
Create the following initializer:
// Compare this with a `UITableViewCell` override init(frame: CGRect) { super.init(frame: frame) } // `required init` hereDetermine what views to create and write a helper function to initialize its properties.
For example, if we need to display some text, we would create a
UILabeland create a helper function to initialize its font, font color, etc. Note that we do not know anything about the data yet, so the property.textof theUILabelwill not be initialized yet.
Inside of the helper function, add the views we created as a subview to
contentViewand constrain the view with respect tocontentView. Then call the helper function inside of the initializer.This is one of the main differences from what we have been doing before. Instead of referencing
view, we will be usingcontentView. Note: we do not need to usesafeAreaLayoutGuidehere.
Create a
configurefunction (do not makeprivate) that will take in some data as a parameter, and configure our views.For example, we could write a function that takes in a
Stringand setsUILabel.textproperty equal to the value passed in.
Create a reuse identifier for this cell:
static let reuse = "<reuse_identifier>"See “Dequeuing Cells” below for more information.
// 1. Subclass of `UICollectionViewCell`
class CustomCollectionViewCell: UICollectionViewCell {
// 3. Create view properties
private let label = UILabel()
// 6. Create a reuse identifier
static let reuse = "CustomCollectionViewCellReuse"
// 2. Create the following init
override init(frame: CGRect) {
super.init(frame: frame)
// 4. Call helper functions
setupLabel()
}
// 2. `required init` here
// 5. `configure` function (do not make private)
func configure(newText: String) {
label.text = newText
// Configure additional views here
}
// 3. Set Up View Helpers
private func setupLabel() {
// 3. Initialize the label's properties
// 4. Add as subview to `contentView`
// 4. Constrain with respect to `contentView`
}
}Dequeuing Cells
The idea behind this concept is the exact same for that of a UITableViewCell. Read it here:
Setting Up a UICollectionView
A UICollectionView is just like any other UIView that we've worked with thus far. We've initialized the view by doing the following steps:
Create the view
Configure the view by changing its properties
Adding the view as a subview to some parent view
Enable auto layout and set up constraint
With a UICollectionView, we do the exact same thing but with additional steps:
Register a
UICollectionViewCellFor example, if we had a custom class called
CustomCollectionViewCellwith a static reuse constant calledreuse, we would use the following code:
collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CustomCollectionViewCell.reuse)Set the
UICollectionViewdelegate (create an extension just like any other protocol)See UICollectionViewDelegate section below
Set the
UICollectionViewdataSource (create an extension just like any other protocol)See UICollectionViewDataSource section below
Every step that we mentioned above is very similar to that of a UITableViewCell; however, there is 1 more additional step.
Initialize the collection view with a
UICollectionViewFlowLayoutand conform toUICollectionViewDelegateFlowLayoutSee UICollectionViewFlowLayout section below
6: UICollectionViewDelegate
The purpose of a UICollectionViewDelegate is to add functionality to the collection view. A class conforming to the protocol UICollectionViewDelegate does not have any required functions to implement; however, the most common function to implement is: didSelectItemAt.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Perform some operation when cell is tapped
}7: UICollectionViewDataSource
In contrast to UICollectionViewDelegate, there are two required functions to implement: cellForItemAt and numberOfItemsInSection. The idea is exactly the same as that of a table view, but with minor syntax changes (”item” instead of “row”).
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataModelArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withIdentifier: CustomCollectionViewCell.reuse, for: indexPath) as? CustomCollectionViewCell else { return UICollectionViewCell() }
let dataModel = dataModelArray[indexPath.row]
cell.configure(...) // pass in our dataModel to the configure function in our custom cell class
return cell
}Read the details here:
8: UICollectionViewFlowLayout
Everything we’ve mentioned earlier is very similar to a table view but with minor syntax changes. However, there is one more additional step that is required by a collection view that gives it customization benefits.
Create a FlowLayout and Initialize CollectionView
Inside of the helper function that sets up the collection view, add the following lines of code:
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = // .vertical or .horizontal
layout.minimumLineSpacing = // (optional) spacing amount
layout.minimumInteritemSpacing = // (optional) spacing amount
// Initialize CollectionView with the layout
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)Let’s go over this line by line:
Create a
UICollectionViewFlowLayoutinstance(REQUIRED) Set the collection view’s scroll direction:
.verticalor.horizontal(OPTIONAL) Set the spacing between each line (top and bottom)
(OPTIONAL) Set the spacing between each item (left and right)
Initialize CollectionView with the layout we just created
Conform to UICollectionViewDelegateFlowLayout
In the previous step, we configured the collection view’s layout. Remember how the UICollectionViewDelegate did not have a heightForRowAt function like a table view does? Well that’s because each item (cell) has a customizable height and width whereas in a table view, we could only customize the row’s height. To do this, just create an extension and conform to UICollectionViewDelegateFlowLayout and add this function:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: <width>, height: <height>)
}Complete Code
class ViewController: UIViewController {
// 1. Create the property BUT DONT INITIALIZE IT YET
// Note that this is different from a table view
private var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Additional setup here
setupCollectionView() // 2. Configure the view
}
// 2. Configure the view
private func setupCollectionView() {
// 8. Create a FlowLayout
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = // .vertical or .horizontal
layout.minimumLineSpacing = // (optional) spacing amount
layout.minimumInteritemSpacing = // (optional) spacing amount
// Initialize CollectionView with the layout
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(CustomTableViewCell.self, forCellWithReuseIdentifier: CustomTableViewCell.reuse) // 5
collectionView.delegate = self // 6
collectionView.dataSource = self // 7
view.addSubview(collectionView) // 3
collectionView.translatesAutoresizingMaskIntoConstraints = false // 4
// 4. Set constraints
}
}
// 6. Conform to `UICollectionViewDelegate`
extension ViewController: UICollectionViewDelegate {
// `didSelectItemAt` (optional)
// Additional functions here
}
// 7. Conform to `UICollectionViewDataSource`
extension ViewController: UICollectionViewDataSource {
// `cellForItemAt`
// `numberOfItemInSection`
// Additional functions here
}
// 8. Conform to `UICollectionViewDelegateFlowLayout`
extension ViewController: UICollectionViewDelegateFlowLayout {
// `sizeForItemAt`
// Additional functions here
}Comparing with a UITableView
A lot of the material mentioned above is very repetitive and already seen in a UITableView. For comparison purposes, here are the main differences between the two when setting them up:
Create a subclass of
UICollectionViewCellinsteadThe
initfunction is different
A flow layout is required when initializing the collection view
You may have noticed that instead of using
private let collectionView = UICollectionView()we usedprivate var collectionView: UICollectionView!. The reason for this is because we have to pass in a layout when initializing the collection view. By replacing it with this line, we are making a promise that we will initialize the collection view later. (There is a cleaner way to do this but it is a bit advanced for now).
You must conform to
UICollectionViewDelegateFlowLayoutImplement the
sizeForItemAtfunction
Syntax: use “items” instead of “rows”
Ex:
cellForItemAtinstead ofcellForRowAt. However, the implementation is the exact same.
Last updated
Was this helpful?