how to set dynamic uicollectionviewcell size from its content - programmatically

2.1k views Asked by At

I need to have just simple UICollectionViewCell style with cells on top of eachoher. Like tableview. But I need Dynamic height dependent of the content, size the content is comments it can vary.

I got viewDidLoad:

  [self.commentsCollectionView registerClass:[GWCommentsCollectionViewCell class] forCellWithReuseIdentifier:@"commentCell"];

in .h I got:

and I #import my custom UICollectionViewCell that sets all constraints with programmatic autolayout.

I instantiate the UICollectionView with:

UICollectionViewFlowLayout *collViewLayout = [[UICollectionViewFlowLayout alloc]init];
self.commentsCollectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:collViewLayout];

I use autolatyout to get the UICollectionView be where I want (thats why CGRectZero).

And finally I was hoping to do this:

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

    GWCommentsCollectionViewCell *cell = (GWCommentsCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];

    return cell.singleCommentContainerview.bounds.size;
}

singleCommentContainerview is a direct subview of the contentView and withing the singleCommentContainerview I have UILabels, UIImageViews etc, all set witih autolayoutcode.

But I just get cgsize value of (0,0)

How can I fix this to get the proper size I need for each cell?

2

There are 2 answers

1
elliotrock On

From what I have read UICollectionView needs the sizes worked out before laying out the cell. So the above method of yours that cell hasn't yet been drawn so it has no size. Also it could be an issue or combined with the issue that the cell is cached/pooled with the same identifier @"commentCell", I tag unique cells with a new identifier and class normally.

My thoughts are to catch the cell before it is drawn, push the size into a dictionary for use later, using:

- (void)collectionView:(UICollectionView *)collectionView
       willDisplayCell:(UICollectionViewCell *)cell
    forItemAtIndexPath:(NSIndexPath *)indexPath{

GWCommentsCollectionViewCell *cell = (GWCommentsCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
// Need to add it to the view maybe in order for it the autolayout to happen
[offScreenView addSubView:cell];
[cell setNeedsLayout];

CGSize *cellSize=cell.singleCommentContainerview.bounds.size
NSString *key=[NSString stringWithFormat:@"%li,%li",indexPath.section,indexPath.row];
// cellAtIndexPath is a NSMutableDictionary  initialised and allocated elsewhere
[cellAtIndexPath setObject:[NSValue valueWithCGSize:cellSize] forKey:key]; 

}

Then when you need it use that dictionary based off the key to get the size.

Its not a really super pretty way as its dependent on the views being drawn, autolayout doing its thing before you get the size. And if you are loading images even more it could throw up issues.

Maybe a better way would be to preprogram the sizes. If you have data on the images sizes that may help. Check this article for a really good tutorial (yah programatically no IB):

https://bradbambara.wordpress.com/2014/05/24/getting-started-with-custom-uicollectionview-layouts/

1
HMHero On

Add

class func size(data: WhateverYourData) -> CGSize { /* calculate size here and     retrun it */} 

to your custom cell and instead of doing

return cell.singleCommentContainerview.bounds.size

it should be

return GWCommentsCollectionViewCell.size(data)