Reputation: 109
I am using Collection View for a scene. I created a custom compositional layout which is like down below. However, while scrolling there is an unwanted space between the second part of the cells. It has occurred in different cell types. I checked the spacing or insets but I couldn't figure out the reason.
The compositional layout part :
struct UIHelper {
static func createLayouts(section: [SectionType], sectionIndex: Int) -> NSCollectionLayoutSection {
switch section[sectionIndex] {
case .sevenDaysWeather(_):
// MARK: - Item
let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(70), heightDimension: .absolute(124))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// MARK: - Group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(124))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
group.interItemSpacing = .fixed(12)
// MARK: - Section
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
// MARK: - Header
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(24))
let headerKind = UICollectionView.elementKindSectionHeader
let headerElement = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: headerKind, alignment: .top)
section.boundarySupplementaryItems = [headerElement]
section.contentInsets = NSDirectionalEdgeInsets(top: 12, leading: 16, bottom: 20, trailing: 0)
return section
}
}
The collection view part:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let type = sections[indexPath.section]
switch type {
case .sevenDaysWeather(let viewModels):
guard let sevenDaysCell = collectionView.dequeueReusableCell(withReuseIdentifier: SevenDaysCollectionViewCell.identifer, for: indexPath) as? SevenDaysCollectionViewCell else { return UICollectionViewCell()}
sevenDaysCell.configure(with: viewModels[indexPath.row])
return sevenDaysCell
}
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: HeaderCollectionReusableView.identifier, for: indexPath) as! HeaderCollectionReusableView
header.configure(section: sections, indexPath: indexPath)
return header
}
}
The current result:
Initial state
Scrolled state
Edit: Normally I have two more sections in the collection view. In order to make the example more clear I trim those parts. But the logic was the same with the given example.
Upvotes: 3
Views: 4558
Reputation: 138
My cells are dynamically sized. So I can't calculate and assign width using .absolute.
Here's a simpler way of doing it:
Set 1 item-per-group using the count param on NSCollectionLayoutGroup. That puts each item in its own group. Then make your groups size themselves dynamically with .estimated width. Set NSCollectionLayoutGroup to vertical for this to work.
let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(175), heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .estimated(175), heightDimension: .absolute(44))
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitem: item, count: 1)
let layoutSection = NSCollectionLayoutSection(group: group)
layoutSection.orthogonalScrollingBehavior = .continuous
return layoutSection
Upvotes: 2
Reputation: 1189
I fixed it like this, but I wonder if there are a cleaner way:
private func makeHorizontalSection(environment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection {
// Calculations
let size = CGSize(width: 100, height: 120)
let insets: CGFloat = 23
let itemSpacing: CGFloat = 4
let availableWidth = environment.container.effectiveContentSize.width - 2 * insets
let itemAndSpaceWidth = size.width + itemSpacing
let numberOfColumns = floor(availableWidth / itemAndSpaceWidth)
let groupWidth: CGFloat = numberOfColumns * itemAndSpaceWidth
// Item
let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(size.width), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// Group
let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(groupWidth), heightDimension: .absolute(size.height))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
group.interItemSpacing = .fixed(itemSpacing)
// Section
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: insets, bottom: 0, trailing: insets)
return section
}
Upvotes: 0
Reputation: 109
After a while, I realized that the problem was related to the width size of the layout group.
In the initial version that I posted, in the compositional layout group properties, I was using fractionalWidth in group size.
Like this:
// MARK: - Group
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(124))
After that, I change the group's width to absolute(widthValue). That fixed the unwanted space.
// MARK: - Group
let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(686), heightDimension: .absolute(120))
Explanation of absolute and fractional can be found in Apple's documentation
Note: I calculated the total widthValue like this:
(numberOfCells * cell widht) + ((numberOfCells - 1) * interSpacingValue)
Upvotes: 2