Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView with dynamic height not getting same space between cell

I am having similar problem like this

I am generating height of view at run time.Here is my code

@interface CollectionViewController ()
{
    NSMutableArray *arrMain;
}
@property(nonatomic,strong) NSMutableArray *arrMain;
@end

@implementation CollectionViewController
@synthesize arrMain,


- (void)viewDidLoad
{
    [super viewDidLoad];

    [cView registerNib:[UINib nibWithNibName:@"CViewCell" bundle:nil] forCellWithReuseIdentifier:kCellID];

    CViewFlowLayout *fl = [[CViewFlowLayout alloc] init];
    self.cView.collectionViewLayout = fl;

    NSString *strJson = MY FUNCTION WHICH RETURNS JSON STRING;
    SBJSON *parser = [[SBJSON alloc] init];

    self.arrMain = [[NSMutableArray alloc] init];
    self.arrMain = [parser objectWithString:strJson error:nil];
    for (int i=0; i<[self.arrMain count]; i++) {
        NSDictionary *dic = [self.arrMain objectAtIndex:i];
        [self setTags:[[UIView alloc] init] selDictionary:dic];  // This function generates height and save it to the dictionary
    }
    [cView reloadData];
}

- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section;
{
    return [self.arrMain count];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{

    NSDictionary *dic = [self.arrMain objectAtIndex:indexPath.row];
    return CGSizeMake(236,40+[[dic valueForKey:@"TAGS_HEIGHT"] intValue]);
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{

    CViewCell *cell =(CViewCell *) [cv dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
    NSDictionary *dic = [self.arrMain objectAtIndex:indexPath.row];
    if ([cell viewWithTag:11]){
        [[cell viewWithTag:11] release];
        [[cell viewWithTag:11] removeFromSuperview];
    }
    UIView *viewTags = [[UIView alloc] init];
    [viewTags setTag:11];
    [viewTags setBackgroundColor:[UIColor lightGrayColor]];
    [self setTags:viewTags selDictionary:dic];
    [viewTags setFrame:CGRectMake(5, 10, CONTENT_WIDTH, [[dic valueForKey:@"TAGS_HEIGHT"] floatValue])];
    [cell.contentView addSubview:viewTags];

    return cell;
}

I had tried above link solution but it is not working for me. Here is an image of my output.

I need the spacing to be same. Is anyone having solution for this issue ?

Is this bug of UICOllectionView ? Because I found this issue in this article also.

like image 595
Viral Narshana Avatar asked Feb 03 '14 12:02

Viral Narshana


4 Answers

I've got the general solution for this kind of problem:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [cView registerNib:[UINib nibWithNibName:@"CViewCell" bundle:nil] forCellWithReuseIdentifier:kCellID];

    CViewFlowLayout *fl = [[CViewFlowLayout alloc] init];
    fl.minimumInteritemSpacing = 10;
    fl.scrollDirection = UICollectionViewScrollDirectionVertical;
    self.cView.collectionViewLayout = fl;

    NSString *strJson = MY FUNCTION WHICH RETURNS JSON STRING;
    SBJSON *parser = [[SBJSON alloc] init];

    self.arrMain = [[NSMutableArray alloc] init];
    self.arrMain = [parser objectWithString:strJson error:nil];
    for (int i=0; i<[self.arrMain count]; i++) {
    NSDictionary *dic = [self.arrMain objectAtIndex:i];
    [self setTags:[[UIView alloc] init] selDictionary:dic];  // This function generates height and save it to the dictionary
}
    [cView reloadData];

}

Then, update the code in CViewFlowLayout.m, which is a subclass of UICollectionViewFlowLayout.

Here is the code:

#define numColumns 3
@implementation CViewFlowLayout
@synthesize numOfColumnsToDisplay;
- (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 (indexPath.item < numColumns){
        CGRect f = currentItemAttributes.frame;
        f.origin.y = 0;
        currentItemAttributes.frame = f;
        return currentItemAttributes;
    }
    NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns inSection:indexPath.section];
    CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
    CGFloat YPointNew = fPrev.origin.y + fPrev.size.height + 10;
    CGRect f = currentItemAttributes.frame;
    f.origin.y = YPointNew;
    currentItemAttributes.frame = f;
    return currentItemAttributes;
}

This solution will work for vertical scrolling only. If you want to display more or less columns, just change the numColumns.

like image 52
Viral Narshana Avatar answered Nov 16 '22 15:11

Viral Narshana


Try this:

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

    return CGSizeMake(250, 150);
}
like image 39
Rajesh Loganathan Avatar answered Nov 16 '22 13:11

Rajesh Loganathan


See this in Storybord or xib set values! enter image description here

like image 1
Muralikrishna Avatar answered Nov 16 '22 15:11

Muralikrishna


The class that you inherited from UICollectionViewFlowLayout must contain methods :

- (CGSize)collectionViewContentSize
{
    return CGSizeMake(200, 200) // as per your cell size
}

- (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];
    }
    return currentItemAttributes;
}

And in Your CollectionViewController add

#pragma mark - Collection View Datasource

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout  *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    // Adjust cell size for orientation
    if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))
    {
        return CGSizeMake(150, 230);
    }
    return CGSizeMake(150, 230);
}
like image 1
Swati Avatar answered Nov 16 '22 13:11

Swati