How to Create Custom Header & Footer Using UIHostingConfiguration
source link: https://swiftsenpai.com/development/uihostingconfiguration-custom-header/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
How to Create Custom Header & Footer Using UIHostingConfiguration
When Apple introduces UIHostingConfiguration
in WWDC, they mainly focus on showcasing how we can use it to create custom cells for table and collection view. This makes me wonder if it is possible to create a custom header and footer using UIHostingConfiguration
.
After a few hours of poking around, it turns out to be totally viable! And the way to make that happen is surprisingly simple. In fact, features such as data binding, animation, and self-resizing all work like a charm on the custom header and footer created using UIHostingConfiguration
.
These are some exciting findings and I can’t wait to share them with you, so let’s get right into it!
Creating the Custom Header and Footer
Supplementary Views Registration
In order to display a custom header and footer, we must first register the custom header and footer to the collection view. Thus let’s go ahead and define the registration objects.
private var headerRegistration: UICollectionView.SupplementaryRegistration<UICollectionViewCell>!
private var footerRegistration: UICollectionView.SupplementaryRegistration<UICollectionViewCell>!
Notice that we are using UICollectionViewCell
as the supplementary view type. Doing so will enable us to define the header and footer using UIHostingConfiguration
when initializing the registration objects.
// Custom header registration
headerRegistration = .init(elementKind: UICollectionView.elementKindSectionHeader) { [unowned self]
(header, elementKind, indexPath) in
// Define header content using `UIHostingConfiguration`
header.contentConfiguration = UIHostingConfiguration {
Text("Header")
.font(.title)
}
}
// Custom footer registration
footerRegistration = .init(elementKind: UICollectionView.elementKindSectionFooter) { [unowned self]
(footer, elementKind, indexPath) in
// Define footer content using `UIHostingConfiguration`
footer.contentConfiguration = UIHostingConfiguration {
Text("Footer")
.font(.title3)
}
}
Both headerRegistration
and footerRegistration
are initialized using the same initializer, just make sure to pass in the correct elementKind
, then you are good to go.
Dequeuing the Supplementary Views
With both of the registration objects in place, we can go ahead and dequeue the custom header and footer. We can do that in the collectionView(_:viewForSupplementaryElementOfKind:at:)
data source method.
func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind elementKind: String,
at indexPath: IndexPath) -> UICollectionReusableView {
switch elementKind {
case UICollectionView.elementKindSectionHeader:
// Dequeue header view using `headerRegistration`
let header = collectionView.dequeueConfiguredReusableSupplementary(
using: headerRegistration,
for: indexPath
)
return header
case UICollectionView.elementKindSectionFooter:
// Dequeue footer view using `footerRegistration`
let footer = collectionView.dequeueConfiguredReusableSupplementary(
using: footerRegistration,
for: indexPath
)
return footer
default:
fatalError("Unexpected element kind")
}
}
Do take note that the elementKind
here must match with the elementKind
that we pass in during the registration object initialization. Otherwise, we will get an NSInternalInconsistencyException
with reason:
The view returned from -collectionView:viewForSupplementaryElementOfKind:atIndexPath: does not match the element kind it is being used for.
Enabling Header & Footer in Compositional Layout
The last piece of the puzzle is to configure the collection view’s layout to show a header and footer.
Here’s how to do it if you are using a compositional list layout:
var layoutConfig = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
layoutConfig.headerMode = .supplementary
layoutConfig.footerMode = .supplementary
let listLayout = UICollectionViewCompositionalLayout.list(using: layoutConfig)
For situation where you are building a custom layout, you can do it like this:
let headerFooterSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(44)
)
let header = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerFooterSize,
elementKind: UICollectionView.elementKindSectionHeader,
alignment: .top
)
let footer = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerFooterSize,
elementKind: UICollectionView.elementKindSectionFooter,
alignment: .bottom
)
let config = UICollectionViewCompositionalLayoutConfiguration()
config.boundarySupplementaryItems = [header, footer]
There you have it, that’s all it takes to create a custom header and footer using UIHostingConfiguration
. Here’s a screenshot of the header and footer we just created.
Up for a Challenge?
At this stage, we can basically create any kind of layout and interaction as long as it is achievable using SwiftUI. Here’s a layout with custom header, footer and cell I build purely using UIHostingConfiguration
and SwiftUI.
Custom header & footer build UIHostingConfiguration and SwiftUI
Do you think you can build one by yourself?
Here are a few tips to get you started:
- You can use the concept presented in this article to create a custom cell.
- Use the cell’s
configurationUpdateHandler
to highlight the selected cell with a red border. You can find out more here. - Use the SwiftUI data binding technique to update the footer with the selected symbol name. More on that here.
- The header height change animation is just a basic SwiftUI transition animation, no extra work needs to be done thanks to the self-resizing nature of
UICollectionViewCell
in iOS 16.
Don’t worry if you somehow get stuck. You can always refer to the full sample code here on Github.
I hope you enjoy reading this article, if you do, feel free to follow me on Twitter and subscribe to my monthly newsletter so that you won’t miss out on any of my upcoming iOS development-related articles.
Thanks for reading. 👨🏻💻
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK