Search code examples
swiftmathuicollectionviewuikituicollectionviewcompositionallayout

How to equally space cells with a fixed size inside a UICollectionView using compositional layout?


I have a collection view created with compositional layout. Each item has a fixed width and height, and the section occupies the full width of the table (which itself occupies the full width of the screen). I'm trying to create an algorithm to calculate the content and section insets in a way that each item has an equal space between them, and also an equal space between the screen's border. In other words, the space between everything should be the same.

Here's the methods to calculate the content and section insets:

// width is 414
private func getContentInsets(width: CGFloat) -> NSDirectionalEdgeInsets {
    let totalItemsInRow = Int(width / 120) // 3
    let totalCellWidth = 120 * totalItemsInRow // 360
    let remainingSpace = width - CGFloat(totalCellWidth) // 54
    let marginPerItem = remainingSpace / CGFloat(totalItemsInRow) // 18
    return NSDirectionalEdgeInsets(top: 8, leading: marginPerItem / 2, bottom: 8, trailing: marginPerItem / 2)
}

// width is 414    
private func getSectionContentInsets(width: CGFloat) -> NSDirectionalEdgeInsets {
    let totalItemsInRow = CGFloat(Int(width / 120)) // 3
    return NSDirectionalEdgeInsets(top: 0,
                                   leading: getContentInsets(width: width).leading * totalItemsInRow, // 9 * 3 = 27
                                   bottom: 0,
                                   trailing: getContentInsets(width: width).trailing * totalItemsInRow) // 9 * 3 = 27
}

Using these methods I was able to have an equal space between the items. But they have a different space to the border of the screen, as we can see on the image bellow:

result of the content and section insets, which centers the items in the middle of the screen, but adds a larger space in the borders

So, how can I change these algorithms to achieve an equal space between the items, and also between the screen borders (everything should have the same spacing).


Solution

  • Thanks to Felipe's idea of assign just the leading value, I was able to fix the algorithm. Unfortunately that formula didn't solved the problem, because a small space was still left at the trailing border of the collection view. And I also noticed that the correct property to use to add space between the cells of the collection view is the edgeSpacing, not the contentInsets.

    So I removed the section inset, and just assigned the edgeSpacing like this:

    private func getEdgeSpacing(width: CGFloat) -> NSCollectionLayoutEdgeSpacing {
        let totalItemsInRow = Int(width / 120)
        let totalCellWidth = 120 * totalItemsInRow
        let remainingSpace = width - CGFloat(totalCellWidth)
        let totalMargins = totalItemsInRow
        let marginPerItem = remainingSpace / CGFloat(totalMargins)
        return NSCollectionLayoutEdgeSpacing(leading: NSCollectionLayoutSpacing.fixed(marginPerItem / 2),
                                             top: nil,
                                             trailing: NSCollectionLayoutSpacing.fixed(marginPerItem / 2),
                                             bottom: nil)
    }
    

    The only fixed value there is 120, which is the fixed width of each cell.