I am making a collage app for that I will be using multiple grid layouts.I am using UICollectionViewCompositionalLayout to create grids. One of my grids requires a heart shaped cell in between. Following is my code the HeartShaped item needs to be heartShape I've no idea how to do it at first I thought of using UIBeizerPath but item is not type of layer and if somehow I manage to do it inside cellForItem still I've many more grids coming and I will have to use "if" "else" again and again. Another problem I am facing my last group i.e the bottom group is not displaying.
Any help would be really appreciated.
let topItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalHeight(1)))
// top items group
let topGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/4)), subitem: topItem, count: 3)
topGroup.contentInsets = .init(top: 0, leading: 3, bottom: 0, trailing: 3)
topGroup.interItemSpacing = .fixed(2)
// middle right item
let middleRightItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/4), heightDimension: .fractionalHeight(1)))
// middle left item
let middleLeftItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/4), heightDimension: .fractionalHeight(1)))
// Heart Shaped
let heartShapedItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/2), heightDimension: .fractionalHeight(1)))
// middle three items group
let middleGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/3)), subitems: [middleRightItem,heartShapedItem,middleLeftItem])
middleGroup.contentInsets = .init(top: 0, leading: 3, bottom: 0, trailing: 3)
middleGroup.interItemSpacing = .fixed(2)
// bottom three items group
let bottomGroup = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1/4)), subitem: topItem, count: 3)
let finalGroup = NSCollectionLayoutGroup.vertical(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1)), subitems: [topGroup,middleGroup,bottomGroup])
finalGroup.interItemSpacing = .fixed(2)
let section = NSCollectionLayoutSection(group: finalGroup)
return section
A collection view layout defines the visual arrangement of the content in your collection - thus in your UICollectionViewCompositionalLayout
you specify such parameters of your collection view like number of items in a row, sizes and offsets, orthogonal scrolling behavior, headers and decoration items, not how a particular cell looks like.
In cellForItem
you could customize your cells including its layers - you could modify shapes there. Cells will be arranged in the collection view based on parameters of your UICollectionViewCompositionalLayout
.
If you are using UICollectionViewDiffableDataSource
, you could differentiate between different type of cells (i.e. cells with a heart shape and a circle shape) with a following code example:
func configureDataSource() {
dataSource = DataSource(collectionView: collectionView) { [self] (collectionView: UICollectionView, indexPath: IndexPath, item: ViewCell) -> UICollectionViewCell? in
switch item.type {
case .heart: return hearCell(for: indexPath)
case .circle: return circleCell(for: indexPath)
default: return normalCell(for: indexPath)
}
}
}
In custom struct ViewCell I have an enum for CellType:
struct ViewCell: Hashable {
var tag: Int
var type: CellType
}
enum CellType { case heart, circle }
Regarding the problem with the bottom group - do you have enough items in your collection view to fill all the groups?
UPDATE:
The problem in your layout is with this line:
middleGroup.interItemSpacing = .fixed(2)
With it 3 rows in the middle group can't be placed in one row. You could remove it and achieve the same spacing by adding insets to the middle item:
heartShapedItem.contentInsets = .init(top: 0, leading: 2, bottom: 0, trailing: 2)
Since you are not using UICollectionViewDiffableDataSource
, you could differentiate your cells by indexPath. So if you have just 1 section, your heartShape item will have indexPath.row of 4:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCollectionViewCell.reuseID, for: indexPath) as? MyCollectionViewCell else { return UICollectionViewCell() }
cell.label.text = "\(indexPath.row)"
cell.label.textAlignment = .center
cell.backgroundColor = .green
if indexPath == IndexPath(row: 4, section: 0) {
cell.label.text = "HEART"
}
return cell
}
(in your original code there is not spacing between items in the bottom group, I don't know if it was done intentionally or not)