Expanding Cells in iOS Collection Views
Learn how to make expanding cells in iOS collection views, as in the Ultravisual app. By Naeem Shaikh.
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
Expanding Cells in iOS Collection Views
25 mins
When Apple introduced collection views with iOS 6 in 2012, many people thought they were the answer to the roadblocks and limitations of customizing table views. Some even proposed to deprecate UITableView
.
Out of the box, UICollectionView
is a powerful and ultra-flexible way to present data in your apps. However, one downside is that, without some level of customization, your app looks bland and fails to stand out among the millions of apps in the App Store.
In this tutorial, you’re going to take a rather plain “templated” app of different colored items and turn it into a visually appeasing way to browse RWDevCon inspiration talk sessions using a collection view.
You’ll add awesome parallax effects and a featured cell item, as well as dabble in subtle fading and transitions to make it really stand out from other apps. The end result is a look and feel similar to the UltraVisual app. If you haven’t seen it, get it now — it’s free!
Note: This tutorial requires a basic knowledge of UICollectionViewController
, or its close cousin UITableViewController
, and an understanding of the basics of the Swift language. If you’re not familiar with it, you can learn more about it in our written or video tutorial series:
- UICollectionView Tutorial Part 1: Getting Started
- UICollectionView Tutorial Part 2: Reusable Views and Cell Selection
- Video Tutorial: Beginning Collection Views
Note: This tutorial requires a basic knowledge of UICollectionViewController
, or its close cousin UITableViewController
, and an understanding of the basics of the Swift language. If you’re not familiar with it, you can learn more about it in our written or video tutorial series:
Ready to stand out with your collection view? Read on!
Getting Started
Download the Ultravisual Kit project using the Download Materials button at the top or bottom of this tutorial. Open the Starter project in Xcode 10. Inside, you’ll find a simple storyboard project with several classes. These are conveniently separated into folders to help you navigate around the project.
The folders contain the following:
- Assets: Contains Images.xcassets, Inspirations.plist and Inspirations.xcassets, which the app uses to load the images for the RWDevCon speakers.
-
Controllers: Contains InspirationsViewController.swift, a
UICollectionViewController
subclass. - Extensions: Contains UIColor+Palette.swift and UIImage+Decompression.swift, which provide convenience methods that handle color conversion and image decompression, respectively. The starter project uses the color palette and, in a future step, you’ll switch to using images and the decompression method.
-
Layouts: Contains UltravisualLayout.swift, which is the meat of the project. As a subclass of
UICollectionViewLayout
,UICollectionView
asks this class for a definition of how to properly lay out and place the items in the collection view. Inside, you’ll find a set of constants and convenience methods that you’ll use to simplify setting up your layout. Additionally, it provides a simple custom cache ofUICollectionViewLayoutAttributes
that are used to modify each cell. - Models: Contains the data models for the background images (Inspiration.swift) and session details (Session.swift); they are separated for the ultimate MVC-pattern win!
- Views: Contains InspirationCell.swift, which handles setting the properties of the collection view cell.
Build and run the starter project, and you’ll see the following:
The app looks decent (if you want a random color palette app, that is), but it doesn’t do much right now. That’s where your job comes in: You’ll turn this clunker into a beautiful app that’s designed to quickly scan through the list of inspirational speakers and topics from RWDevCon.
The technical magic of this project comes from managing the different cell item states:
- The standard cell (what you see in the starter project) that transitions into the “next up” cell, which grows a bit larger.
- The featured cell, which is the largest of all.
You’ll also use a little trickery — modifying the z-index of the cell as it scrolls — for a sweet stacking effect.
Creating Multiple Cell Sizes
First, you’ll create the featured cell. It’ll be roughly twice as large as the standard cell, so a user can clearly see which item is selected.
Jump to UltravisualLayout.swift and go to prepare()
. After this line of code:
cache.removeAll(keepingCapacity: false)
Add a few new local variables that you’ll use across each item:
let standardHeight = UltravisualLayoutConstants.Cell.standardHeight
let featuredHeight = UltravisualLayoutConstants.Cell.featuredHeight
var frame = CGRect.zero
var y: CGFloat = 0
Next, add the following code to loop through each item in the collection view and adjust the item’s state accordingly:
for item in 0..<numberOfItems {
// 1
let indexPath = IndexPath(item: item, section: 0)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
// 2
attributes.zIndex = item
var height = standardHeight
// 3
if indexPath.item == featuredItemIndex {
// 4
let yOffset = standardHeight * nextItemPercentageOffset
y = collectionView!.contentOffset.y - yOffset
height = featuredHeight
} else if indexPath.item == (featuredItemIndex + 1)
&& indexPath.item != numberOfItems {
// 5
let maxY = y + standardHeight
height = standardHeight + max(
(featuredHeight - standardHeight) * nextItemPercentageOffset, 0
)
y = maxY - height
}
// 6
frame = CGRect(x: 0, y: y, width: width, height: height)
attributes.frame = frame
cache.append(attributes)
y = frame.maxY
}
There is a lot going on in the loop, so here's a breakdown:
- Create an index path to the current cell, then create default attributes for it.
- Prepare the cell to move up or down. Since the majority of cells will not be featured — there are many more standard cells than the single featured cells — it defaults to the
standardHeight
. - Determine the current cell's status — featured, next or standard. In the case of the latter, you do nothing.
- If the cell is currently in the featured-cell position, calculate the
yOffset
and use that to derive the newy
value for the cell. After that, you set the cell's height to be the featured height. - If the cell is next in line, you start by calculating the largest
y
could be (in this case, larger than the featured cell) and combine that with a calculated height to end up with the correct value ofy
, which is 280.0 — the height of the featured cell. - Lastly, set some common elements for each cell, including creating the frame, setting the calculated attributes, and updating the cache values. The very last step is to update
y
so that it's at the bottom of the last calculated cell so that you can move down the list of cells efficiently.
For the collection view to know which layout to use, you'll need to tell UICollectionView
to use UltravisualLayout
as its layout class.
First, open Main.storyboard and select the Collection View inside the Document Outline.
Next, open the Attributes inspector and set the Layout dropdown to Custom, and then set the Class to UltravisualLayout
.
Finally, before building, go to InspirationsViewController.swift and, in viewDidLoad()
, remove the last two lines:
let layout = collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSize(width: collectionView!.bounds.width, height: 100)
These two lines were the basic layout to show the equally sized multi-colored cells. Now that you've specified layout code in UltravisualLayout
and set the custom layout class in the storyboard, you no longer need these lines.
Build and run, and you'll see this:
Notice that the top cell is much larger, effectively showcasing a featured cell. As you scroll, the cell below the featured cell expands and overlaps the current featured cell. What a nice effect!