Search code examples
iosobjective-cuicollectionviewuicollectionviewcelluicollectionviewlayout

Create UICollectionView programmatically


I'm trying to teach myself how to use a UICollectionView by building it programatically. I have followed some tutorials to create a sample collection view of size 500 x 500, with each cell being 245 x 45. Thus far, I am able to see the collection view, but it contains no cells and I am not sure why. Here is what I did:

//subclass UICollectionViewLayout

@interface LabelCVLayout : UICollectionViewLayout

@property (nonatomic) UIEdgeInsets itemInsets;
@property (nonatomic) CGSize itemSize;
@property (nonatomic) CGFloat interItemSpacingY;
@property (nonatomic) NSInteger numberOfColumns;

@end

@implementation LabelCVLayout

- (id)init 
{
    self = [super init];
    if (self) {
        [self setup];
    }

    return self;
}

- (void)setup
{
    self.itemInsets = UIEdgeInsetsMake(22.0f, 22.0f, 13.0f, 22.0f);
    self.itemSize = CGSizeMake(245.0f, 45.0f);
    self.interItemSpacingY = 12.0f;
    self.numberOfColumns = 3;
}

@end

//the view controller which displays the collection view

@interface TempViewController () <UICollectionViewDataSource, UICollectionViewDelegate>

@property (strong, nonatomic) UICollectionView *collectionView;

@end

@implementation TempViewController


- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1; 
}

- (NSInteger)collectionView:(UICollectionView *)collectionView
 numberOfItemsInSection:(NSInteger)section
{
    return 4;
}

//THE BELOW DELEGATE METHOD DOES NOT GET CALLED!
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView   cellForItemAtIndexPath:(NSIndexPath *)indexPath
{

    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"newCell" forIndexPath:indexPath];

    cell.backgroundColor = [UIColor whiteColor];

    UILabel *testLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, cell.size.width, cell.size.height)];
    testLabel.font = [UIFont fontWithName:ProximaNovaSemibold size:15];
    testLabel.text = [NSString stringWithFormat:@"Label %i", indexPath.row];
    testLabel.clipsToBounds = YES;
    testLabel.backgroundColor = [UIColor clearColor];
    testLabel.textColor = [UIColor blackColor];
    testLabel.textAlignment = NSTextAlignmentLeft;

    [cell addSubview:testLabel];

    NSLog(@"test!"); //does not print!

    return cell;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    LabelCVLayout *flowLayout = [[LabelCVLayout alloc]init];
    self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0,0,500,500) collectionViewLayout:flowLayout];
    self.collectionView.backgroundColor = [UIColor redColor];
    self.collectionView.dataSource = self;
    self.collectionView.delegate = self;

    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"newCell"];

    [self.view addSubview:self.collectionView];
}

@end

Oddly, after setting breakpoints I discovered that the numberOfSections and numberOfItemsInSection datasource methods ARE getting called, but the cellForItemAtIndexPath method is NOT getting called.

I am wondering if 1) anyone can see what I missed? and 2) if I later want to create a collection view that adds as many cells to a row as will fit based on the size constraints of the cell size and collection view size (i.e. I don't want to have to define a fixed number of columns), do I have to subclass UICollectionViewFlowLayout rather than UICollectionViewLayout?


Solution

  • From what I see your subclass of UICollectionViewLayout is missing some important methods. As that is an abstract class, according to the Apple Documentation here, you have to override the following methods :

    collectionViewContentSize
    layoutAttributesForElementsInRect:
    layoutAttributesForItemAtIndexPath:
    layoutAttributesForSupplementaryViewOfKind:atIndexPath: (if your layout supports supplementary views)
    layoutAttributesForDecorationViewOfKind:atIndexPath: (if your layout supports decoration views)
    shouldInvalidateLayoutForBoundsChange:
    

    This probably explain why the callback isn't called. You may want to switch to the implemented FlowLayout, at least to test it. Finally, regarding 2), I'm unsure of what you want to do, but wouldn't

    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
    

    from the UICollectionViewDelegateFlowLayout do the trick ? Depending of your cell size, you may have a row with 3 cells taking almost all the space, and another with 10 small cells. Feel free to clarify your question if that's not it.