Reputation: 1
When I created the section header I put collectionView there and I want it to attach to the navigation bar when scrolling, I did this through pinToVisibleBounds. The header is attached as I wanted, but when scrolling, going through 1 cell it detaches and leaves the screen.
SectionHeader.swift
class SectionHeader: UICollectionReusableView {
static let reuseId = "SectionHeader"
var sections: [Section] = Bundle.main.decode([Section].self, from: "model.json").filter { section in
return section.type != "Names" && section.type != "Numbers"
}
private var indexPathOfSelectedCell: IndexPath?
fileprivate var collectionView: UICollectionView! = nil
fileprivate var dataSource: UICollectionViewDiffableDataSource<Section, Item>! = nil
override init(frame: CGRect) {
super.init(frame: frame)
cofigureCollectionView()
setupConstraints()
createDataSource()
reloadData()
collectionView.delegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK:- Configure collection view
private func cofigureCollectionView() {
collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: createLayout())
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.layer.shadowOffset = CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
collectionView.backgroundColor = #colorLiteral(red: 0.880524771, green: 0.9031272657, blue: 0.875127862, alpha: 1)
collectionView.alpha = 1
collectionView.register(UINib(nibName: "EmojiCell", bundle: nil), forCellWithReuseIdentifier: EmojiCell.reuseId)
addSubview(self.collectionView)
}
//MARK: - Create layout
private func createLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout {[weak self](sectionIndex: Int,
layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
guard let section = self?.sections[sectionIndex] else { return nil }
switch section.type {
case "Emoji":
return self?.createEmojiSection()
default:
print("There is no such item")
return nil
}
}
return layout
}
//MARK:- Create section
private func createEmojiSection() -> NSCollectionLayoutSection {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 8, bottom: 8, trailing: 8)
let groupSize = NSCollectionLayoutSize(widthDimension: .estimated(120), heightDimension: .estimated(50))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 12, bottom: 0, trailing: 12)
return section
}
//MARK:- setup constraints
private func setupConstraints() {
collectionView.translatesAutoresizingMaskIntoConstraints = false
let inset = CGFloat(10)
NSLayoutConstraint.activate([
self.collectionView.topAnchor.constraint(equalTo: self.topAnchor),
self.collectionView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
self.collectionView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
self.collectionView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -inset)
])
}
//MARK:- Create data source
private func createDataSource() {
dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { [weak self]
(collectionView: UICollectionView, indexPath: IndexPath, item: Item) -> UICollectionViewCell? in
switch self?.sections[indexPath.section].type {
case "Emoji":
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EmojiCell.reuseId, for: indexPath) as? EmojiCell else {return nil}
cell.configureCell(item: item)
return cell
default:
print("There is no such item")
return nil
}
}
}
//MARK:- Reload data
private func reloadData() {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections(sections)
for section in sections {
if section.type == "Emoji" {
snapshot.appendItems(section.items, toSection: section)
}
}
dataSource?.apply(snapshot)
}
}
//MARK:- CollectionView delegate
extension SectionHeader: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let firstItem = self.dataSource.itemIdentifier(for: indexPath) else { return }
let section = self.dataSource.snapshot().sectionIdentifier(containingItem: firstItem)
switch section?.type {
case "Emoji":
let cell = collectionView.cellForItem(at: indexPath)
NotificationCenter.default.post(name: Notification.Name("SelectedIndexPath"), object: nil, userInfo: ["indexPath":indexPath])
if let previousIndex = indexPathOfSelectedCell {
let previousCell = collectionView.cellForItem(at: previousIndex)
previousCell?.backgroundColor = .clear
cell?.backgroundColor = #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1)
} else {
cell?.backgroundColor = #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1)
}
indexPathOfSelectedCell = indexPath
default:
break
}
}
}
Section code
private func createStringSection() -> NSCollectionLayoutSection {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(0.2))
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
let sectionBackgroundDecoration = NSCollectionLayoutDecorationItem.background(
elementKind: ViewController.sectionBackgroundDecorationElementKind)
sectionBackgroundDecoration.contentInsets = NSDirectionalEdgeInsets(top: 80, leading: 0, bottom: 0, trailing: 0)
section.decorationItems = [sectionBackgroundDecoration]
let header = createHeader()
section.boundarySupplementaryItems = [header]
return section
}
Creating header.
private func createHeader() -> NSCollectionLayoutBoundarySupplementaryItem {
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(80))
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top)
header.pinToVisibleBounds = true
header.zIndex = 2
return header
}
I would be very grateful for help, I sit for 4 days can not understand why so.
Here's a gif of what it looks like.
Upvotes: 0
Views: 1614
Reputation: 976
If you want to have a header which is attached to all sections, you should add it to the whole UICollectionViewCompositionalLayout, not to a particular section.
Create an instance of UICollectionViewCompositionalLayoutConfiguration() and add your header items to it:
private func createCompositionalLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout { [self] sectionIndex, layoutEnvironment in
// your code for section
}
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),heightDimension: .estimated(44))
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: "header", alignment: .top)
header.pinToVisibleBounds = true
let config = UICollectionViewCompositionalLayoutConfiguration()
config.boundarySupplementaryItems = [header]
layout.configuration = UICollectionViewCompositionalLayoutConfiguration()
return layout
}
Upvotes: 1