> For the complete documentation index, see [llms.txt](https://ios-course.cornellappdev.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ios-course.cornellappdev.com/resources/archived-past-semesters/sp23/chapters/5.-uicollectionview/lecture-handout.md).

# Lecture Handout

This lecture covers UICollectionViews -- a widely used UIKit component. You'll notice that UICollectionViews are very similar to UITableViews!

## What is a UICollectionView?

A collection view (`UICollectionView`) is a subclass of `UIScrollView`, which means that the user can scroll through it, either horizontally or vertically. Just like a table view, a collection view consists of sections where each section consists of 3 parts: a header, cells, and a footer. However, unlike a table view (in which each cell is constrained to be the full width of the table view), the size of the cells in a collection view can be set. In other words, **a collection view is a more dynamic, customizable table view**.

### Why are UICollectionViews Important?&#x20;

Like table views, `UICollectionView`s are an extremely powerful type of view and are used in almost all of the successful apps today (i.e. Instagram, Photos, Stories, etc.). They provide an easy way to display a lot of information in a compact, **grid-like** manner.&#x20;

### UICollectionView Examples

&#x20;<img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lwk7443W4ukbAF9S07e%2F-M-Db8HICqe8mDxonUr4%2F-M-DdfBkDGzl5oKh9HR_%2Fimage.png?alt=media&amp;token=5ee7b295-08ff-43df-80d1-6d0ae5f70f38" alt="" data-size="original">  <img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lwk7443W4ukbAF9S07e%2F-M-Db8HICqe8mDxonUr4%2F-M-DfPLEMplU6a7db5LS%2Fimage.png?alt=media&amp;token=e1c041bb-c78b-4608-90fc-4934aed1e76a" alt="" data-size="original">&#x20;

Example 1: **Netflix**\
Each category (e.g. "Ensemble TV Shows", "Women Who Rule The Screen", etc.) is a section is a `UICollectionView`. Each show is a `UICollectionViewCell`. &#x20;

Example 2: **Instagram**\
The entire feed is a `UICollectionView`, and each image is a `UICollectionViewCell`.&#x20;

## Using a UICollectionView

### Setting Up a UICollectionView

Similar to a table view, in addition to the usual initialization process for initializing any `UIView` (calling the init function, set `translatesAutoresizingMaskIntoConstraints` to false, adding the view as a subview to parent view, and setting up constraints), there are **4 additional things that you should do**:

1. Set the `collectionView`’s delegate
2. Set the `collectionView`’s dataSource
3. Register your custom `UICollectionViewCell` class
4. **(Only for UICollectionViews!)** Initialize the `collectionView` with a

   `UICollectionViewLayout` (we use `UICollectionViewFlowLayout`). Your `collectionView`’s delegate should also conform to `UICollectionViewDelegateFlowLayout`.

For explanations on what the first 3 mean, refer to [Lecture 4: UITableViews](/resources/archived-past-semesters/sp23/chapters/4.-uitableview/lecture-handout.md).&#x20;

In terms of 4, the initializer for a `UICollectionView` takes in a `frame: CGRect` and a `layout: UICollectionViewLayout`. In most cases, we just use an instance of `UICollectionViewFlowLayout` for this layout parameter. Why? Well, a `UICollectionViewFlowLayout` is a “layout object that organizes items into a grid with optional header and footer views for each section” -- which is what we want in most cases!

Some nice properties of `UICollectionViewFlowLayout` that we can set to customize our `collectionView` are `scrollDirection` (vertical or horizontal), `minimumLineSpacing` (the minimum spacing to use between rows in the grid), `minimumInteritemSpacing` (the minimum spacing to use between items in the same row), and a lot more.

The following is an example of initializing a `UICollectionView`:

```swift
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = padding // optional
layout.minimumInteritemSpacing = padding // optional
collectionView = UICollectionView(frame: .zero, collectionViewLayout:layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(PhotoCollectionViewCell.self,forCellWithReuseIdentifier: photoCellReuseIdentifier)
```

Let's go through what this code does, line by line.\
**1**: Initialize a `UICollectionFlowLayout` instance.\
**2**: Set the layout's `scrollDirection` to be vertically-scrolling.\
**3 & 4**: Set the `minimumLineSpacing` and `minimumInteritemSpacing` to be some constant we defined in a `padding` variable. This means that items in the same row will have spacing between them equal to the value stored in `padding` and items on different rows will also have spacing between them equal to `padding`. (Like the Instagram example!)\
**5**: Initialize our `collectionView` using the `layout` instance we just created.\
**6**: Set `translatesAutoresizingMaskIntoConstraints` to false.\
**7 & 8**: Set the `delegate` and `dataSource` to be `self`, which is the view controller that holds this `collectionView`. \
**9**: Register our custom `PhotoCollectionViewCell` to the `collectionView`. This tells  `collectionView` that we will be dequeueing `PhotoCollectionViewCell`s.&#x20;

### Important Protocols: UICollectionViewDataSource, UICollectionViewDelegate, and UICollectionViewDelegateFlowLayout

We look at this diagram again to understand the delegation that occurs. Even though the diagram uses `UITableViewDataSource` /`UITableViewDelegate`, this is basically the same as `UICollectionViewDataSource`/`UICollectionViewDelegate` except replace “rows” with “items”.

![](https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lwk7443W4ukbAF9S07e%2F-M-Db8HICqe8mDxonUr4%2F-M-DjcqmhLGs27dQREBv%2Fimage.png?alt=media\&token=29f035ee-734c-4b4a-9389-7195e7e67ead)

### 1. UICollectionViewDataSource

A `UICollectionViewDataSource` (in most cases, the view controller) must conform to certain methods and is “**responsible for providing the data and views required by a collection view**.” The one method that you should always implement is:

```swift
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
	let cell = collectionView.dequeueReusableCell(withReuseIdentifier: photoCellReuseIdentifier, for: indexPath) as! PhotoCollectionViewCell
	let dataModel = dataModelArray[indexPath.item]
	cell.configure(for: dataModel)
	return cell
}
```

We'll often refer to this method as `cellForItemAt`. This function requires you to return a `UICollectionViewCell` which will be inserted at a particular location in the `collectionView`.&#x20;

One parameter in this function that is important to take note of is `indexPath`, which is of type `IndexPath`. The `indexPath` has two important properties that you may sometimes need: \
1\. `item` (**Note**: for tableViews, we have rows instead of items), and  \
2\. `section` \
Thus, if you wanted to see what item or section the cell you’re returning is going to be used for, you can just call `indexPath.item` or `indexPath.section`.&#x20;

Once again, let's go through the code line by line:\
**2.** Dequeue the appropriate cell using the associated reuse identifier that you used when you registered your custom cell to the `collectionView`. Make sure you cast the dequeued cell as your custom cell class!\
**3 & 4.** It's best practice to have some `configure(...)` function as a part of your custom cell class that takes in some data or model object to configure the views inside your cell. Let's say you're using some `dataModelArray` as the data source for your collection view. You can access the dataModel object that this item represents using `dataModelArray[indexPath.item]`.\
**5.** Return the configured cell!

Another method that you should implement is:&#x20;

```swift
func collectionView(_ collectionView: UICollectionView, 
numberOfItemsInSection section: Int) -> Int {
   return dataModelArray.count
 }
```

We'll refer to this method as `numberOfItemsInSections`.This function requires you to return an integer representing the number of rows that the section `section` should have. Usually, the number of cells that you want to display in your collection view is dependent on the number of model objects that you have. For example, if you wanted to use a collection view to display a collection of photos, you would probably have an array of Photo objects. Thus, the number of cells you need in your table view is just the number of photos in that array, which you can get from `photosArray.count`. However, it is also possible that you just want to create a static number of cells, in which case you can just return that constant!

Finally, while not required, you may also want to implement the following:

```swift
 func numberOfSections(in collectionView: UICollectionView) -> Int {
   return 2
 }
```

As the name implies, this allows you to control the number of sections that your collection view has. If you don't implement this function, your collection view will by default have one section.&#x20;

### 2. UICollectionViewDelegate

A `UICollectionViewDelegate` does not actually *have* *to* conform to any specific methods since all the methods are optional. However, one useful one that you may find yourself using a lot is:

```swift
func collectionView(_ collectionView: UICollectionView,
 didSelectItemAt indexPath: IndexPath) {
  // Perform some action upon selecting an item
}
```

We'll refer to this function as `didSelectItemAt`. This is the function that gets called whenever one of the cells in `collectionView` is selected by the user. Thus, if you want to trigger some sort of action or animation upon selection, this is the place you would do it. For example, if you wanted to change some data model property upon selecting a cell, you could once again access that specific data model object using `indexPath.item`.

### 3. UICollectionViewFlowLayoutDelegate

Lastly, a `UICollectionViewDelegateFlowLayout` also does not actually have to conform to any specific methods since all the methods are optional. However, a method that you *should* implement is:

```swift
 func collectionView(_ collectionView: UICollectionView, layout
 collectionViewLayout: UICollectionViewLayout, sizeForItemAt
 indexPath: IndexPath) -> CGSize {
   return CGSize(width: 50, height: 50)
 }
```

We'll refer to this method as `sizeForItemAt`. This method requires you to return a `CGSize` that represents the size of the cell at `indexPath`. Thus, if we wanted each of our cells to be 50 pixels by 50 pixels, we would return `CGSize(width: 50, height: 50)`, as in the example code snippet.

## Reference

You can find a list of all the `UICollectionViewDelegate`, `UICollectionViewDataSource`, & `UICollectionViewDelegateFlowLayout` methods in the Apple documentation, linked below.

1. [UICollectionViewDelegate](https://developer.apple.com/documentation/uikit/uicollectionviewdelegate)
2. [UICollectionViewDataSource](https://developer.apple.com/documentation/uikit/uicollectionviewdatasource)
3. [UICollectionViewDelegateFlowLayout](https://developer.apple.com/documentation/uikit/uicollectionviewdelegateflowlayout)

## PDF Download

{% file src="/files/-M-IXfMlR6f7SGw8dSWu" %}
UICollectionViews
{% endfile %}
