12

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.

Community
  • 1
  • 1
Viral Narshana
  • 1,855
  • 2
  • 21
  • 45
  • This is not a bug of UICollectionView. RTFM https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html and have a look at figure 3-4. The way to go is subclass UICollectionViewLayout. – RTasche Jan 06 '16 at 10:02

6 Answers6

7

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.

Albert Bori
  • 9,832
  • 10
  • 51
  • 78
Viral Narshana
  • 1,855
  • 2
  • 21
  • 45
  • 2
    this solution dowes not work well if one cell is two large and second is small. then cells will start appearing too late. Becaseue this cell calls collection view item at indexpath item at there orignal location but then it moves the cell up – Iqbal Khan Nov 26 '14 at 06:06
  • 2
    The problem with UICollectionViewFlowLayout is that it is essentially a grid layout. No matter how big or small the cells in the row are, your row is always going to get the same size as the largest cell -- giving you this weird cell spacing. In order to align all the cells up properly you need to provide a custom UICollectionViewLayout, as described by Albert. To further his code example here is a good example of implementing a custom UICollectionView http://www.objc.io/issue-3/collection-view-layouts.html – AshleyJ Mar 03 '15 at 01:10
3

Try this:

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

    return CGSizeMake(250, 150);
}
Rajesh Loganathan
  • 11,129
  • 4
  • 78
  • 90
1

You can set the size with a property:

flowLayout.headerReferenceSize = CGSizeMake(0, 100);//constant height for all the items header

If Dynamic :

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
    if (section == albumSection) {
        return CGSizeMake(0, 100);
    }

    return CGSizeZero;
}
Kumar KL
  • 15,315
  • 9
  • 38
  • 60
  • 1
    Thanks for answering. I want the cell height dynamic and minimum spacing for lines must be same between all cell not for header. – Viral Narshana Feb 03 '14 at 12:22
  • 1
    Kumar Ki, I am not talking about header space. I want equal space between cell vertically as shown in image. I am having only one section. – Viral Narshana Feb 03 '14 at 12:39
1

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

Muralikrishna
  • 1,044
  • 10
  • 17
  • 1
    Thanks for answering. I checked it and value set over there. I want the cell height dynamic and minimum spacing for lines must be same between all cell. – Viral Narshana Feb 03 '14 at 12:21
  • your cells are not have same height ,you use all cells height and width as same – Muralikrishna Feb 03 '14 at 12:28
  • 1
    Width is same. Height is not same. I am generating height with this line of code 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 } in viewDidLoad – Viral Narshana Feb 03 '14 at 12:31
  • better to use table view to split more cells in one row try it examples also you get in Google – Muralikrishna Feb 03 '14 at 12:42
  • 1
    I can't use table view. See the images in this link. http://stackoverflow.com/questions/14482882/display-images-in-a-uicollectionview-how-to-achieve-fixed-vertical-spacing-bet You will get better idea for my problem. – Viral Narshana Feb 03 '14 at 12:46
1

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);
}
Swati
  • 2,870
  • 7
  • 45
  • 87
  • i can not set fix height in sizeForItemAtIndexPath as i am generating the height of view with this line of code in viewDidLoad method 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 } – Viral Narshana Feb 03 '14 at 12:33
  • cant u call this code in sizeForItemAtIndexPath instead of view did load...coz this method resets all the settings related to size u made in viewdidload – Swati Feb 04 '14 at 06:10
1

Using following method

//Swift

func collectionView(_ collectionView: UICollectionView,
    layout collectionViewLayout: UICollectionViewLayout,
    sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{
 return CGSizeMake(250, 150);
}

//Objective C

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(250, 150);
}