Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to center align the cells of a UICollectionView?

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 
like image 385
RVN Avatar asked Nov 27 '12 16:11

RVN


2 Answers

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.

CenterAlignedCollectionViewFlowLayout

// 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     } } 

CenterAlignedCollectionViewFlowLayout

like image 158
Alex Koshy Avatar answered Sep 28 '22 13:09

Alex Koshy


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.

like image 43
rdelmar Avatar answered Sep 28 '22 11:09

rdelmar