UICollectionView Tutorial: Getting Started
Get hands-on experience with UICollectionView by creating your own grid-based photo browsing app using the Flickr API. By Owen L Brown.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
UICollectionView Tutorial: Getting Started
25 mins
- Anatomy of a UICollectionView
- Using the UICollectionViewLayout
- Introducing FlickrSearch
- Starting Your Collection
- Adding Search
- Subclassing Your UICollectionViewController
- Fetching Flickr Photos
- Flickr API Classes
- Preparing Data Structures
- Getting Good Results
- Feeding the UICollectionView
- UICollectionViewDataSource
- UICollectionViewFlowLayoutDelegate
- Creating Custom UICollectionViewCells
- Subclassing UICollectionViewCell
- Where to Go From Here?
Fetching Flickr Photos
Your first task for this section is to say the section title ten times fast.
OK, just kidding.
Flickr is an image-sharing service with a publicly accessible, and dead-simple, API for developers. With the API, you can search for photos, add photos, comment on photos and much more.
You need an API key to use the Flickr API. If you’re working on a real app, sign up for one at Flickr’s website.
However, for test projects like this, Flickr has a sample key that rotates out every so often. You can use the key without signing up.
Simply perform any search at Flickr’s website and copy the API key from the URL at the bottom. It starts after the &api_key="
goes to the next &
. Paste it in a text editor for later use.
For example, if the URL is:
http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=6593783efea8e7f6dfc6b70bc03d2afb&;format=rest&api_sig=f24f4e98063a9b8ecc8b522b238d5e2f
then the API key is: 6593783efea8e7f6dfc6b70bc03d2afb
With that settled, it’s time to explore the Flickr API classes.
Flickr API Classes
Since this tutorial is about UICollectionView
and not the Flickr API, the project includes classes that abstract the Flickr search code.
The Flickr support consists of two classes and a struct:
- FlickrSearchResults: A struct which wraps up a search term and the results found for that search.
-
FlickrPhoto: Data about a photo retrieved from Flickr: its thumbnail, image and metadata information such as its ID. There are also some methods for building Flickr URLs and some size calculations.
FlickrSearchResults
contains an array of these objects. -
Flickr: Provides a simple block-based API to perform a search and return a
FlickrSearchResult
.
Feel free to take a look at the code. It’s pretty simple and might inspire you to use Flickr in your projects!
Before you can search Flickr, you need to enter an API key. Open Flickr.swift. Replace the value of apiKey
with the API key you obtained earlier.
It’ll look something like this:
let apiKey = "hh7ef5ce0a54b6f5b8fbc36865eb5b32"
Now, it’s time to do a little prep work before hooking into Flickr.
Preparing Data Structures
In this project, each search you perform displays a new section in the collection view with the results, rather than replacing the previous section. In other words, if you search for ninjas and then pirates, you’ll see a section of ninjas and a section of pirates in the collection view. Talk about a recipe for disaster!
To create these separate sections, you need a data structure to keep each section’s data separate. An array of FlickrSearchResults
will do the trick.
Open FlickrPhotosViewController.swift. Add the following properties below sectionInsets
:
private var searches: [FlickrSearchResults] = []
private let flickr = Flickr()
searches
is an array that keeps track of all the searches made in the app. flickr
is a reference to the object that searches for you.
Next, add the following extension to the bottom of the file:
// MARK: - Private
private extension FlickrPhotosViewController {
func photo(for indexPath: IndexPath) -> FlickrPhoto {
return searches[indexPath.section].searchResults[indexPath.row]
}
}
photo(for:)
is a convenience method that gets a specific photo related to an index path in your collection view. You’ll access a photo for a specific index path a lot, and you don’t want to repeat code.
You’re now ready to get your Flickr search on!
Getting Good Results
When the user taps Search after typing in a query, you want the search to execute. You already connected the text field’s delegate outlet to your collection view controller. Now you can do something about it.
Open FlickrPhotosViewController.swift. Add an extension to hold the text field delegate methods:
// MARK: - Text Field Delegate
extension FlickrPhotosViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
guard
let text = textField.text,
!text.isEmpty
else { return true }
// 1
let activityIndicator = UIActivityIndicatorView(style: .gray)
textField.addSubview(activityIndicator)
activityIndicator.frame = textField.bounds
activityIndicator.startAnimating()
flickr.searchFlickr(for: text) { searchResults in
DispatchQueue.main.async {
activityIndicator.removeFromSuperview()
switch searchResults {
case .failure(let error) :
// 2
print("Error Searching: \(error)")
case .success(let results):
// 3
print("""
Found \(results.searchResults.count) \
matching \(results.searchTerm)
""")
self.searches.insert(results, at: 0)
// 4
self.collectionView?.reloadData()
}
}
}
textField.text = nil
textField.resignFirstResponder()
return true
}
}
Here’s a code breakdown:
- After adding an activity view, you use the Flickr wrapper class to search Flickr asynchronously for photos that match the given search term. When the search completes, you call the completion block with the result set of
FlickrPhoto
objects and any errors. - You log any errors to the console. Obviously, in a production app, you would want to show the user these errors.
- Then, you log the results and add them at the beginning of the searches array.
- Finally, you refresh the UI to show the new data. You use
reloadData()
, which works as it does in a table view.
Build and run. Perform a search in the text box. You’ll see a log message in the console indicating the number of search results like this:
Found 20 matching bananas
Note that the Flickr helper limits the results to 20 to keep load times down.
Unfortunately, you don’t see any photos in your collection view! A collection view doesn’t do much unless you implement the relevant data source and delegate methods, similar to a table view.
You’ll do that in the next section.
Feeding the UICollectionView
When you use a table view, you have to set a data source and delegate to provide the data to display and handle events, like row selection.
Similarly, when you use a collection view, you have to set a data source and delegate as well. Their roles are as follows:
- The data source,
UICollectionViewDataSource
, returns information about the number of items in the collection view and their views. - The delegate,
UICollectionViewDelegate
, gets another notification when events happen, such as when a user selects, highlights or removes a cell.
UICollectionViewFlowLayout
also has a delegate protocol, UICollectionViewDelegateFlowLayout
. It lets you tweak the layout’s behavior to configure things like cell spacing, scroll direction and cell size. You can learn more in this Apple documentation.
In this section, you’ll implement the required UICollectionViewDataSource
and UICollectionViewDelegateFlowLayout
on your view controller, so you’re set up to work with your collection view. The UICollectionViewDelegate
isn’t required for this tutorial, but you’ll use it in UICollectionView: Reusable Views Selection Reordering.
Time to connect the data source!