I want to add separators on list-like collection view built with compositional layout. I know there is a solution in iOS 14, but I support iOS 13. I try to add separators as supplementary view to every cell in section.
First, I register my supplementary in collection view.
collectionView.register(
supplementaryClass: CollectionReusableView<SeparatorView>.self,
ofKind: .separator
)
Then I provide actual view in DataSource.
func collectionView(
_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath
) -> UICollectionReusableView {
switch kind {
case UICollectionView.SupplementaryKind.separator.rawValue:
return collectionView.dequeue(
decorationClass: CollectionReusableView<SeparatorView>.self,
ofKind: .separator,
for: indexPath
)
default:
assertionFailure("Unexpected element kind: \(kind).")
return UICollectionReusableView()
}
}
And finally, I layout item with separator.
let separator = NSCollectionLayoutSupplementaryItem(
layoutSize: separatorSize,
elementKind: UICollectionView.SupplementaryKind.separator.rawValue,
containerAnchor: separatorAnchor
)
let item = NSCollectionLayoutItem(
layoutSize: itemSize,
supplementaryItems: [separator]
)
When I open my screen and UICollectionView.reloadData() is called, app crashes with this:
Every supplementary must have a unique elementKind
What am I doing wrong? Xcode 13.3
Because each NSCollectionLayoutSupplementaryItem should have a unique element kind.
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
I've solved this issue by creating new SupplementaryViewOfKind on UICollectionViewCompositionalLayoutSectionProvider.
let uniqueItemId: String = /* */
let elementKind: String = UICollectionView.SupplementaryKind.separator.rawValue + uniqueItemId
/* register a new elementKind on UICollectionView */
collectionView.register(ReusableView.self, forSupplementaryViewOfKind: elementKind, withReuseIdentifier: reuseIdentifier)
let separator = NSCollectionLayoutSupplementaryItem(
layoutSize: separatorSize,
elementKind: elementKind,
containerAnchor: separatorAnchor
)
let item = NSCollectionLayoutItem(
layoutSize: itemSize,
supplementaryItems: [separator]
)
on your collectionView(_:viewForSupplementaryElementOfKind:at:), it should be
func collectionView(
_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath
) -> UICollectionReusableView {
if kind.contains(UICollectionView.SupplementaryKind.separator.rawValue) {
return collectionView.dequeue(
decorationClass: CollectionReusableView<SeparatorView>.self,
ofKind: .separator,
for: indexPath
)
} else {
assertionFailure("Unexpected element kind: \(kind).")
return UICollectionReusableView()
}
}
But I don't think it's a great idea.
If you want to check that SupplementaryViewOfKind is already registered on UICollectionView, use private method named -[UICollectionView _hasRegisteredClassOrNibForSupplementaryViewOfKind:].
Then you can avoid repetition of same SupplementaryViewOfKind registration on UICollectionView, but it's not a necessary thing.
let uniqueItemId: String = /* */
let elementKind: String = UICollectionView.SupplementaryKind.separator.rawValue + uniqueItemId
let didRegister: Bool = collectionView._hasRegisteredClassOrNibForSupplementaryView(ofKind: elementKind)
if !didRegister {
/* register a new elementKind on UICollectionView */
collectionView.register(ReusableView.self, forSupplementaryViewOfKind: elementKind, withReuseIdentifier: reuseIdentifier)
}
let separator = NSCollectionLayoutSupplementaryItem(
layoutSize: separatorSize,
elementKind: elementKind,
containerAnchor: separatorAnchor
)
let item = NSCollectionLayoutItem(
layoutSize: itemSize,
supplementaryItems: [separator]
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With