Learn how to build lists and sidebars in your app with UICollectionView. Replace table view appearance while taking advantage of the full flexibility of compositional layout. Explore modular layout options and find out how they can unlock more design options for your apps than ever before. Find out how to combine table view-like lists with custom compositional layouts inside of a single UICollectionView. Discover how to work with lists, create richer cells, and customize your layout to create a well-designed presentation of information within your app.
To get the most out of this session, you should have a basic understanding of compositional layouts. Watch “Advances in Collection View Layout” from WWDC19 for more information.
Hello and welcome. My name is Michael Ochs. I am Frameworks Engineer on the UIKit team and in this video we're going to talk about lists and UICollectionView. What you can see here is the architecture that we consider part of a modern collection view setup and this diagram is covered in detail in Advances In Collection View. There are individual videos for the different parts of this diagram and in this video we're covering List Configuration and List Cell. But let's first talk about what Lists in Collection Views actually are. Lists in iOS 14 give you UITableView-like appearances in UICollectionView. We rebuild it on top of Compositional Layout, which we introduced In iOS 13. That makes it very flexible and highly customizable. We also greatly improve the self-sizing support, specifically for lists, and are making self-sizing the new default behavior when using lists in UICollectionView.
What that means is, you no longer need to worry about manually calculating the height of your cells, but instead you can simply build your cells using AutoLayout and collection view will take care of the rest for you.
If you do require manual sizing though, you can still do this by overriding preferredLayoutAttributesFittingAttributes: on your cell subclasses.
But let's circle back to the customization aspect and take a look at what I mean when I say highly customizable. Here you can see an example of an app that shows all my recently used emojis in the top row, scrolling orthogonally.
Below that you see an outline that sorts all the emojis by group and has this hierarchy built into it. And then at the bottom we have something that looks a lot more like a UITableView. And in addition, you can also swipe each of the cells to mark your favorite emojis. What you see here is a single Collection View using a combination of lists and compositional layout. Before we dig deeper into how this works, let's take a look at the components of a list. In iOS 14 we're offering a new type called UICollectionLayoutListConfiguration. This is the only new type that is required on the layout side to build lists in collection view. UICollectionLayoutListConfiguration is built on top of NSCollectionLayoutSection as well as UICollectionViewCompositionalLayout which are both part of the existing compositional layout system we introduced in iOS 13.
We're not going to cover compositional layout in detail in this talk, So if you're not familiar with it I highly recommend you to check out Advances in Collection View Layout from WWDC 2019. But now let's take a look at List Configuration. List configuration gives you the same appearances that you already know from table view as styles - .plain, .grouped and .insetGrouped.
But we're also introducing two new styles exclusive to lists in UICollectionView which we call .sidebar and .sidebarPlain and you can use these new styles to build amazing multicolumn apps on iPadOS 14. In addition to the general appearance, list configuration also gives you the option to show or hide separators as well as to configure the headers and footers of your list. All this terminology on list configuration should sound familiar to you if you have used UITableView before, but we did add a couple of new bells and whistles that we're going to talk about in a minute. But first let's take a look at how to create a list.
The easiest way to create a list is to create a UICollectionLayoutListConfiguration, give it an appearance and then create an UICollectionViewCompositionalLayout using this configuration. In this example, we're using the .insetGrouped style which will make this look exactly like an inset grouped UITableView, with every section in this layout looking the same. So it's very similar to UITableView and I recommend you to use this approach when possible. However there's a much more powerful way to create a list and we call this the per-section setup. In the per-section setup you use the exact same configuration, but instead of creating a compositional layout with it, you create an NSCollectionLayoutSection using this configuration.
This code can then be used inside the existing section provider initializer on compositional layout, which will then be called for every section in your collection view, allowing you to return an individual layout definition specific to the particular section. What you see here will result in the exact same design than the simple setup that I showed you earlier. However now that we have this setup, we can start customizing our layout on a per section basis. For example, here, for the first section, I'm returning a custom grid layout that I built using the existing compositional layout APIs.
This is very powerful and can be used for layouts like the one you saw earlier in the video where I showed you the orthogonal scrolling section of my recently used emojis. Now that you've seen how to create lists in UICollectionView, let's talk about how to configure your headers and footers in a list section.
Headers and footers in lists in collection views work a bit different than what you're used to from UITableView. Headers and footers in UICollectionView have to be explicitly enabled and there are two ways to do this.
The first way is to register your headers and footers as supplementary views.
In this example we're going to configure a header, but the same code also works for footers. Simply set either the header or the footer mode on the configuration to 'supplementary'.
Next, when configured that way, collection view will ask you to provide a supplementary view when it's time to render your header or footer on screen.
The easiest way to provide this view is through a supplementaryViewProvider on your diffable data source but you can also implement the equivalent method on your UICollectionView delegate.
Inside of this callback you can then check the elementKind for either elementKindSectionHeader or elementKindSectionFooter and configure and return the appropriate view.
It's important to keep in mind that, when using this approach, you have to provide a supplementary view when the collection view asks you to. If you return nil in the supplementary view callback, collection view will assert. So if some sections in your layout require a header while others don't, simply use the per-section configuration that I showed you earlier and set the mode to either supplementary or none depending on whether this particular section should show a header or not. I mentioned there are two options. The second option is only available for headers, and is enabled by setting the headerMode to firstItemInSection. This tells the collection view to configure the first cell in this particular section to look like a header.
This mode is the mode we're recommending when you're using hierarchical data structures and the new section snapshot APIs. You can learn all about how this works in Advances in Diffable Data Source. However, keep in mind that when using this mode, your data source needs to be aware of this, because the first item in your data source no longer represents the actual content of your section but rather the header, probably just a title, of this section.
OK now that we have covered the layout of lists in collection view, let's talk about the presentation side. In iOS 14 we're introducing a new UICollectionViewCell subclass, called UICollectionViewListCell.
It's worth mentioning that, staying true to the compositional nature of collection views, you can use a list sell anywhere a regular collection view cell is expected, and also you can just use any UICollectionViewCell with lists sections. So you can just pick the bits and pieces of the API that you need in order to achieve the design that you are aiming for.
So let's take a look at what the pieces are that list cell can help you with.
List cell has more fine grained support to configure the insets of separators as well as the indentation of your cell's content. In contrast to UITableView, Swipe Actions are now also a feature of the cell.
Furthermore we have a greatly improved accessories API and of course you have access to the default system content and background configurations that you can learn all about in the video Modern Cell Configuration.
So let's talk about separators.
Here you can see an example of a cell that is rendering an image and a label and a separator beneath it. It's a pretty common layout. However as you might have noticed, the layout you can see here is actually not correct.
The separator is supposed to line up with the primary content of your cell, which in this example is not the image view but rather the label of the cell. So on the leading side, the separator is supposed to be inset to match the edge of this label. Like this.
On UITableView, this is done by providing a point based value, called a separator inset. This was pretty easy when this API was introduced because you probably already had a method that manually calculated the X offset of your label and so you could just use the same method to also configure the separator inset with the same value. However, in the modern AutoLayout world where you have safe area insets, layout margins, dynamic font sizes and SF Symbols, this is not that easy anymore. Today we have a highly dynamic environment where all these values could change at any time. With dynamic fonts and SF Symbols even the size of your image could change depending on the preferred font size of your users and then alter the position of the label. So it's pretty hard to know upfront where the label is going to end up. In list cell we're introducing a new concept we're calling the Separator Layout Guide.
This layout guide works a bit different than the existing layout guides in UIKit. Instead of constraining your content to this layout guide, you can constrain this layout guide to your content. So it's the opposite of what you're used to when working with layout guides. The easiest way to set up the separator layout guide is to configure you cell's layout first and once your cell looks the way you intended it to, simply add a single additional constraint.
Constrain the separator layout guides leading anchor to your label's leading anchor, or to whatever the primary content is in your cell. Lists cell, together with list section will then make sure to automatically keep the separator aligned with the primary content of your cell.
Note that if you're using the system provided content configurations we will do this automatically for you and you don't have to worry about any of this. But if you have custom cell layouts, this is an easy way to make sure the separator is positioned correctly. Now, let's talk about Swipe Actions.
In contrast to UITableView, swipe actions are now a feature of list cell. You configure them together with the content of your cell. So wherever you configure the image view or the labels of your cell you can now also set the leading or trailing swipe actions configuration. This requires communication between the cell and the layout, so swipe actions are only supported if your cell is rendered inside of a section that was configured using a list configuration. If you require the dynamic nature of the swipe action API we had on UITableView where you only create the swipe configuration when the swipe is about to start, you can override the leading or trailing swipe actions configuration getter and then create the configuration in there. We will make sure to only call the getter when the user actually attempts to swipe the cell. A word of caution: in the action handler of your swipe actions, make sure to never capture the index path of the cell you're configuring! The index path is not a stable identifier. The index path of this cell changes whenever you're inserting or deleting content above it which doesn't necessarily reload this particular cell. So if you use a stored index path to fetch the data model of the cell when the user triggers a swipe action, you might actually operate on the data of another cell. This is particularly dangerous for the delete action as you might delete the wrong data. Instead, either capture the data model directly or a stable identifier that you can use to identify the content of this cell.
Diffable Data Source and its stable item identifiers as well as the new cell registration type in iOS 14, are a perfect fit for this.
Next let's talk about accessories.
On UITableView, the accessories API was fairly limited. You had access to an accessory type and an accessory view which were mutually exclusive and were only relevant for the trailing side of your cell. List cell offers many new accessory types and also allows you to configure accessories for both, the trailing and the leading side of the cell and you can even configure multiple accessories on the same side.
Furthermore, where on UITableViewCell accessories were more like decoration views, in list cell they can enable functionality.
For example, if you configure a cell with the re-ordering accessory we will automatically put the collection view in re-ordering mode when the user taps this accessory, assuming you also implement the necessary reorder callbacks.
Another example is the delete accessory which was previously known as the delete edit control. If the user taps this accessory, list cell will automatically reveal any configured trailing swipe actions of your cell. And we also have a brand new accessory, the outline disclosure accessory. When the user taps this accessory, the cell will automatically communicate with the data source and expand or collapse the children of this cell. This requires the use of the new section snapshot APIs and you can learn all about that in Advances in Diffable Data Source. Now let's take a look at how the API works. In order to configure the accessories of your cell all you have to do is to set a single accessories property on list cell to an array of UICellAccessories. For this example I'm going to configure this cell with a disclosure indicator and a delete accessory. The system knows that the disclosure indicator is supposed to always be on the trailing side of your cell, whereas the delete accessory always shows on the leading side of your cell. So UIKit will automatically sort accessories in the correct order and show them on the appropriate side. Furthermore, the system also knows that while the disclosure indicator is supposed to be visible all the time, the delete accessory should only be visible when the collection views is in editing mode. So UIKit will automatically animate the delete accessory in or out when entering or exiting edit mode.
We provide a lot of these system defaults but we allow you to customize almost all of them. For example, if you want the disclosure indicator to only be visible when not an editing mode, simply set the displayed parameter to whenNotEditing. This is a super declarative API where UIKit takes care of all the states for you. As you've seen, lists are a highly customizable layout that is very modular and flexible. It is super easy to adopt. So go check out the sample code and play around with it, there is a lot more to discover in there. And once you familiarize yourself with the new APIs, think about where you could enhance the layouts in your app. Think about where you could replace an existing table view and make use of the flexibility to mix lists with any custom compositional layout. And of course also check out all the other videos we have on UICollectionView. There are a lot more amazing features in collection views in iOS 14.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.