Updated 2 February 2021
UICollectionView implements a collection view that has sticky rows and columns and supports both vertical and horizontal scrolling using Swift. Using StickyLayout quick and simple. First import StickyLayout. You then have the option of creating an instance of StickyConfig, where you can specify which rows/columns you want to be sticky. Create an instance of StickyLayout with your StickyConfig as a parameter, and add it to your UICollectionView.
Let execute Sticky Rows and Columns with Collection view
Step 1. create a collection view in your main controller
and define collection view in your controller for example
1 2 3 4 5 |
@IBOutlet weak var gridCollectionView: UICollectionView! { didSet { gridCollectionView.bounces = false } } |
create a grid layout of your collection view as StickyGridCollectionViewLayout
1 2 3 4 5 6 |
@IBOutlet weak var gridLayout: StickyGridCollectionViewLayout! { didSet { gridLayout.stickyRowsCount = 1 gridLayout.stickyColumnsCount = 1 } } |
For now, let’s ignore the compiler’s warnings to better understand the logic flow.
rowsCount
 and columnsCount(in:)
 later.xOffset
. Attributes of each row are stored in an array.xOffset
 and yOffset
 to position the cell correctly within the grid. The size is received from the new method size(forRow:,column:)
 that will be implemented later.allAttributes
 that contains attributes for the whole grid.
Collection view data source and delegate methods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
func numberOfSections(in collectionView: UICollectionView) -> Int { return 20 } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 20 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.reuseID, for: indexPath) as? CollectionViewCell else { return UICollectionViewCell() } cell.titleLabel.text = "test \(indexPath)" cell.backgroundColor = gridLayout.isItemSticky(at: indexPath) ? .groupTableViewBackground : .white return cell } |
Define layout size of your collection view cell
1 2 3 |
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: 100, height: 100) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class StickyGridCollectionViewLayout: UICollectionViewFlowLayout { var stickyRowsCount = 0 { didSet { invalidateLayout() } } var stickyColumnsCount = 0 { didSet { invalidateLayout() } } private var allAttributes: [[UICollectionViewLayoutAttributes]] = [] private var contentSize = CGSize.zero func isItemSticky(at indexPath: IndexPath) -> Bool { return indexPath.item < stickyColumnsCount || indexPath.section < stickyRowsCount } |
 Collection view flow layout methods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
override var collectionViewContentSize: CGSize { return contentSize } override func prepare() { setupAttributes() updateStickyItemsPositions() let lastItemFrame = allAttributes.last?.last?.frame ?? .zero contentSize = CGSize(width: lastItemFrame.maxX, height: lastItemFrame.maxY) } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var layoutAttributes = [UICollectionViewLayoutAttributes]() for rowAttrs in allAttributes { for itemAttrs in rowAttrs where rect.intersects(itemAttrs.frame) { layoutAttributes.append(itemAttrs) } } return layoutAttributes } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true } |
Put size of your Collection view Cell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
private var rowsCount: Int { return collectionView!.numberOfSections } private func columnsCount(in row: Int) -> Int { return collectionView!.numberOfItems(inSection: row) } private func size(forRow row: Int, column: Int) -> CGSize { guard let delegate = collectionView?.delegate as? UICollectionViewDelegateFlowLayout, let size = delegate.collectionView?(collectionView!, layout: self, sizeForItemAt: IndexPath(row: row, column: column)) else { assertionFailure("Implement collectionView(_,layout:,sizeForItemAt: in UICollectionViewDelegateFlowLayout") return .zero } return size } |
You can see the output below
For more detail please click here
I hope this blog helped with any query please leave a comment to us and for more blogs please click here.
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views
I can’t do it.