UICollection Compositional Layout Part 3
In previous part we covered the advanced topic of compositional layout . In this part we will be working with supplementary view . Now that we are comfortable with the base implementation, this part of the series will focus on the Supplementary Items and Decorations that we can use in a Compositional Layout and the way to implement them.
CollectionView manages three basic view class types: Your cells, the things you interact with to express your model objects; it also represents supplementary items and decoration items. Now, these are meant to adorn other parts of your layout to give you visual cues about content information, like maybe a badge on a cell that says, “Hey, you got a comment on your tweet,” or whatever.
And we see common uses for these today with these three examples — badges, and headers, and footers. And we have support and flow today with sticky headers and footers. And they float above that content. But we extend this in compositional layout, making this a whole lot easier. And we can simplify this with this notion of being able to anchor content onto an item or group in your layout. It simplifies that visual relationship, how that might work. All right, let’s look at this visually. So here we can see we’ve got this new type, NSCollectionLayoutAnchor.
Create a Badge Supplementary View
As shown in Figure 1
- First we define an
NSCollectionLayoutAnchor
for our badge. By specifying[.top, .trailing]
we position our badge in the top right corner of the parent, while thefractionalOffset
positions our badge’s center in the the corner. AfractionalOffset
of.zero
would position the whole badge inside the parent. - As encountered before, we need to create a size for our item, so here we specify that we our badge should have a fixed value for width and height
- We initialise our
NSCollectionLayoutSupplementaryItem
by assigning it the size, the anchor and anelementKind
, based upon which we will identify our badge incollectionView:viewForSupplementaryElementOfKind:atIndexPath:
. - Now that we have our badge ready, we just need to assign it to our items. To do so just replace
NSCollectionLayoutItem
initialiser and add supplementaryItems and passed badge
So here we see we have NSCollectionLayoutAnchor we create right away. And we specify the edges. We want this item to be pinned to the top trailing side of that particular cell. And we want it to poke outside of that geometry a little bit. And we see that with fractional height. we see here that items have these little notifiers on them, right, letting them know, And with this, they kind of poke outside that geometry a little bit, right? They’re not really inside the geometry of the cell itself. So that fractionalOffset is what buys us the ability to poke outside a little bit. We’re going to move over fractionally 30% in the positive X and then up in the minus Y 30% as well. And then we see we defined the CollectionLayout SupplementaryItem with a badgeSize and elementKind. So we’re going to refer back to the view class for CollectionView with that registered supplementary type.And then we specify the container’s anchor, specifying how it’s going to relate. So now that we have this definition of our supplementary, we need to associate it with something. And that needs to be associated with an item, a cell. So in this case we’re going to initialize it with an extended variant of initializer that takes an array of supplementaries. And that’s it.
As shown in Figure 3 we moved the badge to top left / leading and fractionalOffset : is the offset from item , so we specify zero and it will anchor badge within the item. Few things to be cover
- If we want to tell Compositional Layout we want supplementary views, we need to associate them with
NSCollectionLayoutItem or
NSCollectionLayoutGroup. This can be done either with init or later with thesupplementaryItems
property. Both cases expect an array ofNSCollectionLayoutSupplementaryItem
. This is a class that lets us define the supplementary items. You can’t addNSCollectionLayoutSupplementaryItem
item on section. For section we have NSCollectionLayoutBoundarySupplementaryItem which we will see in next section
NSCollectionLayoutAnchor →
An object that defines how to attach a supplementary item to an item in a collection view.You use an anchor to attach a supplementary item to a specific item. An anchor contains information about where on the item your supplementary item is attached, including:
An edge or set of edges. You can attach a supplementary item to a single edge, or to a corner by specifying two adjacent edges. An offset from the item. By default, the supplementary item is anchored within the specified edges of the item it’s attached to. You can change this location by providing a custom offset when you create an anchor.
Code for Badge User interface
As shown in Figure 5 we did few things
- create a badge , anchor it to item which is cell
- Then create a group assign item to a group
- Finally we create
sectionHeader
NSCollectionLayoutBoundarySupplementaryItem
, give it layoutheaderFooterSize
and give alignment to header as top and footer bottom. Note headerFooterSize is dynamic which means it will grow as the content increase this is happen because we provide estimated height instead of absolute - Then we supply
boundarySupplementaryItems
and pass header and footer to section
boundarySupplementaryItems →
An array of the supplementary items that are associated with the boundary edges of the section, such as headers and footers.
NSCollectionLayoutSupplementaryItem →
An object used to add headers or footers to a collection view. A boundary supplementary item is a specialized type of supplementary item (NSCollectionLayoutSupplementaryItem). You use boundary supplementary items to add headers or footers to a section of a collection view or the entire collection view. Each type of supplementary item must have a unique element kind. Consider tracking these strings together in a way that makes it straightforward to identify each element.
struct ElementKind {
static let badge = "badge-element-kind"
static let background = "background-element-kind"
static let sectionHeader = "section-header-element-kind"
static let sectionFooter = "section-footer-element-kind"
static let layoutHeader = "layout-header-element-kind"
static let layoutFooter = "layout-footer-element-kind"
}
As shown in Figure 6 , Diffable Data Source has supplementaryViewProvider property we can use to provide supplementary views. This can be a closure or you can define method that takes collection view, element kind and indexPath and assign this method.
Register supplementary view is very important otherwise app will crash
As shown in Figure 8 , we pinned header and footer
pinToVisibleBounds → A Boolean value that indicates whether a header or footer is pinned to the top or bottom visible boundary of the section or layout it’s attached to. The default value of this property is false, which means that the boundary supplementary item (header or footer) remains in its original position during scrolling, and moves offscreen as its section or layout scrolls. Set the value of this property to true to pin the boundary supplementary item to the visible bounds of the section or layout it’s attached to. This way, the boundary supplementary item is shown while any portion of the section or layout it’s attached to is visible.
Gif 2 you see header pin at top and footer pin ad bottom but we have one problem our badge view over lap header and footer
As shown in Figure 9 we change zindex
zindex →
The vertical stacking order of the supplementary item in relation to other items in the section. This property is used to determine the front-to-back ordering of items during layout. Items with higher index values appear on top of items with lower values. Items with the same value have an undetermined order.
Now we added two badge in each item, note each supplementary item should have unique elementKind Also one thing elementKind could be any string. The below struct is just a template constants provided by apple
struct ElementKind {
static let badge = "badge-element-kind"
static let background = "background-element-kind"
static let sectionHeader = "section-header-element-kind"
static let sectionFooter = "section-footer-element-kind"
static let layoutHeader = "layout-header-element-kind"
static let layoutFooter = "layout-footer-element-kind"
}
DataSource
Register supplementary View
As shown in Figure 14 we anchor yellow badge View to a group and green badge to a item , Note: we can’t do with section.
Decoration Items
In addition to supplementary items, we can customize our section layout with decoration items. This will allow us to easily add backgrounds to our sections. The background view we’ll create is quite simple (a gray rectangle with a corner radius), so we’ll do it in code
All right. So by now you’ve played around with the brand new iOS 13 card presentation, this whole card design language all throughout the system. And we see this in scrolling UI’s as well where all kinds of content is grouped together logically with cards. And this is a natural fit for CollectionView because we always had support for notions of decoration views. Well, in the past you had to do the math yourself. Well, now we’ve made it a lot simpler with compositional layout. And we support this with a CollectionLayoutDecorationItem. You just create it with an element kind and you’re done. This is intended to be used to have a view that’s behind the section content itself to give you that nice visual grouping. And to construct it, there’s just one line of code. And then to add it to the section, you just want to specify the items and off you go
As shown in Figure 15 we created layout for background view that will show for each section and we register with layout
layout.register(BackgroundSupplementaryView.self, forDecorationViewOfKind: “background”) →
Registers a class for use in creating decoration views for a collection view. This method gives the layout object a chance to register a decoration view for use in the collection view. Decoration views provide visual adornments to a section or to the entire collection view but are not otherwise tied to the data provided by the collection view’s data source.You do not need to create decoration views explicitly. After registering one, it is up to the layout object to decide when a decoration view is needed and return the corresponding layout attributes from its layoutAttributesForElements(in:) method. For layout attributes that specify a decoration view, the collection view creates (or reuses) a view and displays it automatically based on the registered information.
If you previously registered a class or nib file with the same kind string, the class you specify in the viewClass parameter replaces the old entry. You may specify nil for viewClass if you want to unregister the decoration view.
The background card view that shows each section background view as a card
Global Header , Footer and Decorative View
As shown in Figure 17 we added header and footer globally to layout instead of section, since section and footer pinToVisibleBounds
is true so it will be visible to screen
UICollectionViewCompositionalLayoutConfiguration →
An object that defines scroll direction, section spacing, and headers or footers for the layout.You use a layout configuration to modify a collection view layout’s default scroll direction, add extra spacing between each section of the layout, and add headers or footers to the entire layout. You can pass in this configuration when creating a UICollectionViewCompositionalLayout, or you can set the configuration property on an existing layout. If you modify the configuration on an existing layout, the system invalidates the layout so that it will be updated with the new configuration.
As shown in Figure 18 now pinToVisibleBounds comment out ow when you scroll global header and footer will scroll as well