I'm attempting to define a custom flow layout for a UICollectionView by subclassing UICollectionViewFlowLayout. The layout I want looks like this:
As you can see, I have split the collection view into 2 equal rows along the horizontal middle divide. The top row is split into thirds to give 3 columns, and the bottom rows split in half to give 2 columns.
Everything seems to work and look fine until you scroll to the right (the collection view scrolling is to UICollectionViewScrollDirectionHorizontal), and see there a large space after the 5 cells have finished being rendered:
I have no idea why this is happening, however it does appear that the empty space looks about the same width as a cell from the top row; a third of the width of the collection view.
Here is how I setup the UICollectionView and UICollectionViewFlowLayout subclass
- (void)loadView {
[super loadView];
[self setupCollectionView];
}
- (void)setupCollectionView {
CustomFlowLayout *flowLayout = [[CustomFlowLayout alloc] init];
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.minimumInteritemSpacing = 0.0;
flowLayout.minimumLineSpacing = 0.0f;
CGRect frame = CGRectMake(0, 0, 748, 1024);
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:flowLayout];
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CollectionViewCellID];
collectionView.delegate = self;
collectionView.dataSource = self;
collectionView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
collectionView.backgroundColor = [UIColor whiteColor];
collectionView.pagingEnabled = YES;
self.collectionView = collectionView;
[self.view addSubview:self.collectionView];
}
#pragma mark - UICollectionViewDataSource
- (NSInteger )numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 5;
}
The size of the items in the collection view is defined by the layout configuration for a given section, so I implement collectionView:layout:sizeForItemAtIndexPath:
like so:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return [collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath].size;
}
My custom subclass of UICollectionViewLayout is implemented as follows:
@implementation CustomFlowLayout
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
if (nil == attributes.representedElementKind) {
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes* currentItemAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
if (!currentItemAttributes) {
currentItemAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
}
float height = self.collectionView.frame.size.height;
float width = self.collectionView.frame.size.width;
CGRect frame = CGRectZero;
switch (indexPath.row) {
case 0:
frame.size = CGSizeMake(width/3, height/2);
frame.origin = CGPointMake(0, 0);
break;
case 1:
frame.size = CGSizeMake(width/3, height/2);
frame.origin = CGPointMake(width/3, 0);
break;
case 2:
frame.size = CGSizeMake(width/3, height/2);
frame.origin = CGPointMake(2*width/3, 0);
break;
case 3:
frame.size = CGSizeMake(width/2, height/2);
frame.origin = CGPointMake(0, height/2);
break;
case 4:
frame.size = CGSizeMake(width/2, height/2);
frame.origin = CGPointMake(width/2, height/2);
break;
default:
break;
}
currentItemAttributes.frame = frame;
currentItemAttributes.size = frame.size;
return currentItemAttributes;
}
Anyone got any ideas why I have the large empty space after all the cells have been rendered? Or does anyone have a better approach to rendering the layout I am after. All the code is available as a sample XCode project here. Answers, tips, thoughts, pull requests are greatly appreciated.
The problem seemed to be that when there were two rows of cells that had different widths the contentSize of the collectionview was being calculated in such a way that left an area of white space to the right. A simple was necessary to fix the problem:
- (CGSize)collectionViewContentSize {
return CGSizeMake(1024, 748);
}
Updated the Github repo with the changes here. Hope this helps someone in the future.
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