TUTORIAL: Using UICollectionView with UICollectionViewFlowLayout

Showing data in a gridview is a beautiful and space-saving solution for graphical data (e.g movies, books, pictures etc). It has been popular long before Apple introduced UICollectionView in iOS 6 – a powerful and highly customisable way to show gridviews in iOS.

Before iOS 6 there were many ways to create a grid, including usage of UITableViews, UIScrollViews and custom open-source components. However, none of solutions was as powerful and as easy to use like UICollectionView.

This tutorial will cover a basic usage scenario of UICollectionView. It will use the default layout that is called UICollectionViewFlowLayout. For most apps it is sufficient. The next tutorial will show, how to create custom layouts.

CollectionView Components

CollectionView implementation is separated between different Objects:

  • UICollectionView defines a visible area for its cells. It subclasses UIScrollView and therefore inherits all UIScrollView options like contentOffset or scrollEnabled.
  • UICollectionReusableView – All UICollectionView children must be subclasses of UICollectionReusableView. UICollectionReusableView provides basic view recycling mechanism to improve performance for big data sets. Usually it is not used directly for content items, but it is used for footer and header views.
  • UICollectionViewCell is a specific type of UICollectionReusableView for content items.
  • UICollectionViewLayout defines a frame for each cell and computes the total contentSize. UICollectionView highly depends on UICollectionViewLayout in determining cell locations and the total scrollable area.
  • UICollectionViewFlowLayout is the built-in layout that subclasses UICollectionViewLayout and is used to implement simple grids. The layout is highly customisable.

The demo app

We are going to build a gridview with some beautiful nature pictures. It can be used as a category view for a gallery or a photo app.

UICollectionView1

 

Complete code

You can find the complete code here (tested with Xcode 8.1, iOS 10.1):

 

Getting started

Open Xcode and create a new project by choosing the Single View Application template. Choose iPad under “Devices”. Choose whether Swift or Objective-C on the screen. This tutorial covers both Swift and Objective-C.

UICollectionView2

Now let’s design the main user interface. Open Main.storyboard that should already have a single ViewController. Open the Object Library and find the UICollectionView object.

UICollectionView3

Drag the UICollectionView to the ViewController’s view. Setup autolayout constraints to fill the superview with a small top offset (25px), so the collectionview does not overlap with a statusbar.

dPTtDc4Nxg

It is also possible to use UICollectionViewController, but in most cases it is smarter to use just UICollectionView. If you wish to use UICollectionViewController, just replace the ViewController with UICollectionViewController in the Main.storyboard and add a new corresponding subclass of UICollectionViewController. All other steps should be similar.

UICollectionView5

Now open the Attributes Inspector of the UICollectionView. Here you can see multiple options including layout, scroll direction and accessories. For static data it is possible to set the exact number of items and design all items in the Interface Builder. We will design in the Interface Builder only one cell, so items count can be set to 1. Chose “Flow” for the layout option, because we will use a built-in UICollectionViewFlowLayout for this tutorial. The important part is to mark the “Section header” option under Accessories, so the collectionview will have a header view.

IZMdPYzY1u

After those modifications the collectionview should have two subviews: a UICollectionReusableView and a UICollectionViewCell.

UICollectionView7

Let’s now design the headerview. Open the Object Library and pick the UILabel object. Drag it to the header view (UICollectionReusableView). Change the font as you like and add constraints to center the label inside the headerview.

UICollectionView8

UICollectionView9

Select the collectionview and change cell size to 300×300 px. This value will be overridden in code; we’ll make it bigger just for convenience. If cell sizes must be static, put here real sizes.

UICollectionView10

Drag the UIImageView from the Object Library to UICollectionViewCell. Add appropriate autolayout constraints (fill superview with a small inset of 10 px on all sides).

UICollectionView11

Adding classes

For content cells and the headerview we’ll use corresponding subclasses.

Add a new class “GalleryItemCommentView”, which extends “UICollectionReusableView”. It will also have an IBOutlet for UILabel.

Objective-C:

 Swift:

Also add a class for content cells. Name it “GalleryItemCollectionViewCell”. It should subclass UICollectionViewCell.

Objective-C:

 Swift:

Let’s also add some convenience implementation to the GalleryItemCollectionViewCell class, so that we can update reusable cells easier:

Objective-C:

Swift:

As you see, it also has an IBOutlet for UIImageView. The method “setGalleryItem:” just sets the image.

And here is the implementation for “GalleryItem”. It’s a simple model object that contains a single gallery image.

Objective-C:

Swift:

Finalizing user interface

Go back to the Storyboard and make some final changes. Select the headerview and set both its class and identifier to “GalleryItemCommentView”. Correspondingly, change the class and identifier of UICollectionViewCell to “GalleryItemCollectionViewCell”.

UICollectionView12

UICollectionView13

Connect UILabel from the headerview and UIImageView from the cell to their corresponding IBOutlets.

Add a UICollectionView outlet to the ViewController and connect it in the storyboard.

Objective-C:

Swift:

UICollectionView14

Finally, add UICollectionViewDataSource and UICollectionViewDelegate protocols declarations to the ViewController. In the storyboard connect UICollectionView’s dataSource and delegate with the ViewController.

Objective-C:

Swift:

8ec6QUR4Cz

<UICollectionViewDataSource, UICollectionViewDelegate>

We are almost done. We only need to create some data objects and implement UICollectionViewDataSource/UICollectionViewDelegate protocols.

Creating data objects is straightforward:

1. Add some pictures to assets. You can download pictures for this demo project HERE.

2. Add a new plist file. Name it items.plist. It will contain a list of all gallery items.

3. Declare array for galleryItems in the ViewController:

Objective-C:

Swift:

4.Read gallery items from the plist file and create corresponding model items:

Objective-C:

Swift:

Call initGalleryItems in viewDidLoad and reload the collectionview afterwards.

Objective-C:

Swift:

UICollectionViewDataSource

The next step is to implement UICollectionViewDataSource.

numberOfSectionsInCollectionView: is an optional method to return number of sections, which is useless to implement in terms of this demo project, but might be important for real projects:

Objective-C:

Swift:

It is 1 by default, but if you need multiple sections, it should be implemented.

Then add a required method collectionView:numberOfItemsInSection: to return number of items in section:

Objective-C:

Swift:

The total number of gallery model items is returned here.

To create cells implement cellForItemAtIndexPath:

Objective-C:

Swift:

Because we designed our cell in the storyboard and changed both its identifier and class, the dequeueReusableCellWithReuseIdentifier: will return the correct class.

To use a separate xib for a cell, UICollectionView has a handy method registerClass:forCellWithReuseIdentifier:. It should be implemented before calling dequeueReusableCellWithReuseIdentifier:.

There’s a similar method for supplementary views. Supplementary views are usually used to implement the header and the footer view.

We’ll implement only the header view using collectionView:viewForSupplementaryElementOfKind:atIndexPath: method:

Objective-C:

Swift:

UICollectionViewDelegate

To track selection of cells, use UICollectionViewDelegate. It has many options, including deselecting, highlighting, unhighlighting etc. Obviously, the most interesting is the cell selection:

Objective-C:

Swift:

Our demo app will just show an alert when an item is selected.

The last step is to dynamically change cell sizes and insets. Using a constant height or width might sometimes be not enough. UICollectionViewFlowLayout has multiple options that can also be changed dynamically by implementing UICollectionViewDelegateFlowLayout.

Objective-C:

Swift:

Here we change dynamically some layout options, so our gridview will look nice in both portrait and landscape modes.

The collectionview will redraw its children during the orientation change without any extra action. Thus, you don’t need to call extra reloadData during the orientation change. UICollectionViewFlowLayout will automatically change spacing between cells and cell sizes.

Everything looks as expected:

sample_img

Complete code

You can find the complete code here (tested with Xcode 8.1, iOS 10.1):

 

9 Comments
  1. Frank
  2. ugajin
  3. Matthew
    • iOSDev iOSDev
  4. kranthi
  5. Doris
    • iOSDev iOSDev
  6. Ghazanfar
  7. Shrike

Leave a Reply

Your email address will not be published. Required fields are marked *

*