Horizontal UICollectionViewLayout with Sticky HeaderView
platforms Swift Package Manager pod License
- iOS9+
- tvOS9+
Just implement these 5 required delegate methods.
extension ViewController: HorizontalStickyHeaderLayoutDelegate { private enum Const { static let headerSize = CGSize(width: 100, height: 38) static let itemSize0 = CGSize(width: 50, height: 50) static let itemSize1 = CGSize(width: 80, height: 80) static let headerLeft: CGFloat = 8 } func collectionView(_ collectionView: UICollectionView, hshlSizeForItemAtIndexPath indexPath: IndexPath) -> CGSize { if indexPath.section % 2 == 0 { return Const.itemSize0 } else { return Const.itemSize1 } } func collectionView(_ collectionView: UICollectionView, hshlSizeForHeaderAtSection section: Int) -> CGSize { return Const.headerSize } func collectionView(_ collectionView: UICollectionView, hshlHeaderInsetsAtSection section: Int) -> UIEdgeInsets { return UIEdgeInsets(top: 0, left: Const.headerLeft, bottom: 20, right: 20) } func collectionView(_ collectionView: UICollectionView, hshlMinSpacingForCellsAtSection section: Int) -> CGFloat { return 20 } func collectionView(_ collectionView: UICollectionView, hshlSectionInsetsAtSection section: Int) -> UIEdgeInsets { return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: section == 4 ? 0 : 20) } }
Optionally you can define contentInset for outer margin.
See Example for detail.
- On focus, call
updatePoppingHeaderIndexPaths()to recalculate the popping header indexPaths to get the latest indexPaths. - Listen to pop indexPaths change on scroll by implementing
collectionView(_:,hshlDidUpdatePoppingHeaderIndexPaths:)delegate method. - animate container view of your header view.
See Example for recommended implementation.
// Either in UICollectionViewDelegate or this override method. override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { layout.updatePoppingHeaderIndexPaths() let (pop, unpop) = self.getHeaders(poppingHeadersIndexPaths: self.layout.poppingHeaderIndexPaths) UIView.animate(withDuration: Const.unpopDuration, delay: 0, options: [.curveEaseOut], animations: { unpop.forEach { 0ドル.unpopHeader() } }, completion: nil) coordinator.addCoordinatedAnimations({ pop.forEach { 0ドル.popHeader() } }, completion: nil) super.didUpdateFocus(in: context, with: coordinator) } func collectionView(_ collectionView: UICollectionView, hshlDidUpdatePoppingHeaderIndexPaths indexPaths: [IndexPath]) { let (pop, unpop) = self.getHeaders(poppingHeadersIndexPaths: self.layout.poppingHeaderIndexPaths) UIView.animate(withDuration: Const.unpopDuration, delay: 0, options: [.curveEaseOut], animations: { unpop.forEach { 0ドル.unpopHeader() } pop.forEach { 0ドル.popHeader() } }, completion: nil) }
Install via Xcode.
pod "HorizontalStickyHeaderLayout"
MIT