I am currently using UICollectionView
for the user interface grid, and it works fine. However, I'd like to be enable horizontal scrolling. The grid supports 8 items per page and when the total number of items are, say 4, this is how the items should be arranged with horizontal scroll direction enabled:
0 0 x x 0 0 x x
Here 0 -> Collection Item and x -> Empty Cells
Is there a way to make them center aligned like:
x 0 0 x x 0 0 x
So that the content looks more clean?
Also the below arrangement might also be a solution I am expecting.
0 0 0 0 x x x x
For those looking for a solution to center-aligned, dynamic-width collectionview cells, as I was, I ended up modifying Angel's answer for a left-aligned version to create a center-aligned subclass for UICollectionViewFlowLayout
.
// NOTE: Doesn't work for horizontal layout! class CenterAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let superAttributes = super.layoutAttributesForElements(in: rect) else { return nil } // Copy each item to prevent "UICollectionViewFlowLayout has cached frame mismatch" warning guard let attributes = NSArray(array: superAttributes, copyItems: true) as? [UICollectionViewLayoutAttributes] else { return nil } // Constants let leftPadding: CGFloat = 8 let interItemSpacing = minimumInteritemSpacing // 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 } }
I think you can achieve the single line look by implementing something like this:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { return UIEdgeInsetsMake(0, 100, 0, 0); }
You will have to play around with that number to figure out how to force the content into a single line. The first 0, is the top edge argument, you could adjust that one too, if you want to center the content vertically in the screen.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With