Hightower98 Hightower98 - 4 months ago 19
iOS Question

Centering UICollectionView Cells in Container

Hi I need help centering my collection view cells via UICollectionViewFlowLayout. My end goal is to have the first cell in the middle and have every other cell snapping in the middle. Thanks!

Here is what it looks like now:
enter image description here

and what I want it to look like:
enter image description here

I found this "solution" on SO but it seems to not work properly.

class CenterAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

let attributes = super.layoutAttributesForElementsInRect(rect)

// Constants
let leftPadding: CGFloat = 8
let interItemSpacing: CGFloat = 5

// Tracking values
var leftMargin: CGFloat = leftPadding // Modified to determine origin.x for each item
var maxY: CGFloat = -1.0 // Modified to determine origin.y for each item
var rowSizes: [[CGFloat]] = [] // Tracks the starting and ending x-values for the first and last item in the row
var currentRow: Int = 0 // Tracks the current row
attributes?.forEach { layoutAttribute in

// Each layoutAttribute represents its own item
if layoutAttribute.frame.origin.y >= maxY {

// This layoutAttribute represents the left-most item in the row
leftMargin = leftPadding

// Register its origin.x in rowSizes for use later
if rowSizes.count == 0 {
// Add to first row
rowSizes = [[leftMargin, 0]]
} else {
// Append a new row
rowSizes.append([leftMargin, 0])
currentRow += 1
}
}

layoutAttribute.frame.origin.x = leftMargin

leftMargin += layoutAttribute.frame.width + interItemSpacing
maxY = max(layoutAttribute.frame.maxY, maxY)

// Add right-most x value for last item in the row
rowSizes[currentRow][1] = leftMargin - interItemSpacing
}

// At this point, all cells are left aligned
// Reset tracking values and add extra left padding to center align entire row
leftMargin = leftPadding
maxY = -1.0
currentRow = 0
attributes?.forEach { layoutAttribute in

// Each layoutAttribute is its own item
if layoutAttribute.frame.origin.y >= maxY {

// This layoutAttribute represents the left-most item in the row
leftMargin = leftPadding

// Need to bump it up by an appended margin
let rowWidth = rowSizes[currentRow][1] - rowSizes[currentRow][0] // last.x - first.x
let appendedMargin = (collectionView!.frame.width - leftPadding - rowWidth - leftPadding) / 2
leftMargin += appendedMargin

currentRow += 1
}

layoutAttribute.frame.origin.x = leftMargin

leftMargin += layoutAttribute.frame.width + interItemSpacing
maxY = max(layoutAttribute.frame.maxY, maxY)
}

return attributes
}

Answer

Make sure your view controller is the delegate of the collection view and implement the following method from UICollectionViewDelegateFlowLayout:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
    let sideInset = (collectionView.frame.size.width - myCollectionViewCellSize.width) / 2
    return UIEdgeInsets(top: 0, left: sideInset, bottom: 0, right: sideInset)
}
Comments