Hi 👋 Given I have a UICollectionView
using a UICollectionViewCompositionalLayout
.
The layout contains of a single group containing 3 full-width items.
The orthogonalScrollingBehavior
behaviour of the section is set to .paging
.
The section includes a header in which a UISegmentedControl
is presented.
Here's what I want to achieve:
- User changes the segmented control: The value change (
selectedIndex
) of the segmented control alters the presented page in the collection view (currently viascrollToItem(at:at:animated:)
). - User swipes the paging collection view: When the user swipes the pages, the segmentedControl has to be changed to reflect the current page
Here's my problem:
- When I use the segmented control to navigate through the pages, the sections
visibleItemsInvalidationHandler
fires and updates the segmented control with (temporary) invalid values.
This causes some UI glitches in the segmented control. I can't rely on the UIScrollView
delegate because the collection view seems to use a different scroll view for the paging mechanism internally.
Question
- Is there a way to intercept the
visibleItemsInvalidationHandler
for the time the collection view animates thescrollToItem(at:at:animated:)
changes? - Or is there any other alternative to the
visibleItemsInvalidationHandler
which is called only once after the transition is done?
Here's my layout setup:
private func makeCompositionalLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(300)
)
let padding: CGFloat = 16
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(
top: 0,
leading: padding,
bottom: 0,
trailing: padding
)
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
let header = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerSize,
elementKind: MyCollectionReusableView.sectionHeaderElementKind,
alignment: .top
)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(300))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .paging
section.visibleItemsInvalidationHandler = { [weak self] _, contentOffset, _ in
guard let self, let collectionView else { return }
let pageWidth = collectionView.bounds.width
let fractionalPage = contentOffset.x / pageWidth
segmentedControlDelegate?.update(idx: lround(fractionalPage))
}
section.boundarySupplementaryItems = [header]
return UICollectionViewCompositionalLayout(section: section)
}