mzdogan
mzdogan

Reputation: 109

Unwanted space between Collection View cells Compositional Layout

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 wanted result: Wanted Result

The current result: Initial state Initial Scrolled state Unwanted space

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

Answers (3)

theogood
theogood

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

manueGE
manueGE

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

mzdogan
mzdogan

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))

Result: Initial Initial Position

Scrolled Scrolled Position

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

Related Questions