Reputation: 319
I am trying to layout a UICollectionView like the mock-up I have drawn in the photo(also showing the index of each item):
The code I currently have to try and achieve this is:
In ViewDidLoad:
collectionView.dataSource = self
collectionView.delegate = self
flowLayout.scrollDirection = .horizontal
flowLayout.minimumLineSpacing = 5
flowLayout.minimumInteritemSpacing = 5
flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 5)
Then later on the the file:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let totalWidth = collectionView.bounds.size.width
let totalHeight = collectionView.bounds.size.height
let heightOfView = totalHeight / 3
let numberOfCellsPerRow = 1
let dimensions = CGFloat(Int(totalWidth) / numberOfCellsPerRow)
if (indexPath.item == 4) {
return CGSize(width: collectionView.bounds.size.width, height: heightOfView)
} else {
return CGSize(width: dimensions / 2, height: heightOfView)
}
}
This code isn't having the desired effect, and is producing a UICollectionView that looks like this:
As you can see, the cells are not even in the UICollectionView
, with the right-hand side cells overflowing into scroll space. The section gaps between the items are wrong and the 5th, the larger cell is on the right-hand side of the screen out of view unless scrolled to.
Upvotes: 0
Views: 1156
Reputation: 5945
You cannot create such layout with standard UICollectionViewFlowLayout class. First of all watch WWDC videos related to UICollectionView and it's layout: https://developer.apple.com/videos/play/wwdc2012/219/. Then you can check Swift tutorials with sample code to get started: http://swiftiostutorials.com/tutorial-creating-custom-layouts-uicollectionview/
Simplest working, but not best structured will be such code in custom UICollectionViewLayout
. Use this as a starting point:
@interface UICollectionViewCustomLayout ()
@property (nonatomic) NSArray<UICollectionViewLayoutAttributes *> *attributes;
@property (nonatomic) CGSize size;
@end
@implementation UICollectionViewCustomLayout
- (void)prepareLayout
{
[super prepareLayout];
NSMutableArray<UICollectionViewLayoutAttributes *> *attributes = [NSMutableArray new];
id<UICollectionViewDelegate> delegate = (id<UICollectionViewDelegate>)self.collectionView.delegate;
id<UICollectionViewDataSource> dataSource = (id<UICollectionViewDataSource>)self.collectionView.dataSource;
NSInteger count = [dataSource collectionView:self.collectionView numberOfItemsInSection:0];
CGFloat collectionViewWidth = CGRectGetWidth(self.collectionView.frame);
CGFloat collectionViewHeight = CGRectGetHeight(self.collectionView.frame);
CGFloat rowHeight = floor(collectionViewHeight / 3);
NSUInteger numberOfPages = count / 5;
if (count % 5) {
numberOfPages++;
}
for (NSInteger item = 0; item < count; item++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:0];
UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
NSInteger index = item % 5;
NSInteger page = item / 5;
CGFloat width = index == 4 ? collectionViewWidth : collectionViewWidth / 2;
CGSize size = CGSizeMake(width, rowHeight);
CGFloat x = page * collectionViewWidth + (index % 2 == 0 ? 0 : collectionViewWidth / 2);
CGFloat y = (index / 2) * rowHeight;
CGPoint origin = CGPointMake(x, y);
CGRect frame = CGRectZero;
frame.size = size;
frame.origin = origin;
attribute.frame = frame;
[attributes addObject:attribute];
}
self.attributes = attributes;
self.size = CGSizeMake(numberOfPages * collectionViewWidth, collectionViewHeight);
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray<UICollectionViewLayoutAttributes *> *result = [NSMutableArray new];
for (UICollectionViewLayoutAttributes *attribute in self.attributes) {
if (CGRectIntersectsRect(attribute.frame, rect)) {
[result addObject:attribute];
}
}
return result;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"indexPath.section == %@ AND indexPath.item == %@", @(indexPath.section), @(indexPath.item)];
UICollectionViewLayoutAttributes *attributes = [self.attributes filteredArrayUsingPredicate:predicate].firstObject;
return attributes;
}
- (CGSize)collectionViewContentSize
{
return self.size;
}
@end
And controller:
// Views
#import "UICollectionViewCustomLayout.h"
@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic) UICollectionView *collectionView;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:[UICollectionViewCustomLayout new]];
self.collectionView.backgroundColor = [UIColor whiteColor];
self.collectionView.frame = self.view.bounds;
self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([UICollectionViewCell class])];
[self.view addSubview:self.collectionView];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 10;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
NSArray *colors = @[[UIColor redColor], [UIColor blueColor], [UIColor grayColor], [UIColor greenColor], [UIColor purpleColor], [UIColor cyanColor]];
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([UICollectionViewCell class]) forIndexPath:indexPath];
cell.contentView.backgroundColor = colors[arc4random() % colors.count];
cell.contentView.alpha = (arc4random() % 500 + 500) / 1000.0;
return cell;
}
@end
Upvotes: 1