2

I am trying to create custom tiled layout using UICollectionView. It renders perfectly as desired in simulator once I run my app.

But the moment I scroll the view and bring it back all the cell's frame changes and the cells get overlapped, leaving spaces, randomly.

I am not able to solve this issue past 2 days. Here goes the code from my custom layout class.

-(void)prepareLayout{
[self createCellSizeArray];//cellSizeArray holds cell sizes for all the cells(calculated statically) 
[self createAttributeArrayOfAll];//attributeArrayOfAll holds attributes for all the cells and also calculates their frames using cellSizeArray
}

-(CGSize)collectionViewContentSize{
   return CGSizeMake(768, 1500);//The size is static to check for scrolling, is this creating problems?
}

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
      UICollectionViewLayoutAttributes * layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
      return layoutAttributes;
}

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
    NSMutableArray *attArray =[NSMutableArray array];
    for (NSInteger i =0; i< attributeArrayOfAll.count; i++) {
    UICollectionViewLayoutAttributes * attribute = (UICollectionViewLayoutAttributes*)[attributeArrayOfAll objectAtIndex:i];
    if(CGRectIntersectsRect(rect, attribute.frame)){
        [attArray addObject:attribute];
    }
}
return attArray;
}

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
  return YES;
}

Please help, Thanks in advance.

Edit: In my [self createAttributeArrayOfAll]; I have these lines of code

CGRect frame = CGRectMake(_startNewRowPoint.x, _startNewRowPoint.y, cellSize.width, cellSize.height);
 UICollectionViewLayoutAttributes * attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
 attribute.alpha = 1.0;
 attribute.frame = frame;
 [attributeArrayOfAll addObject:attribute];

While I modified layoutAttributesForItemAtIndexPath:, to look something like this

-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
 UICollectionViewLayoutAttributes * layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
 layoutAttributes.frame = ((UICollectionViewLayoutAttributes*)[attributeArrayOfAll objectAtIndex:indexPath.item]).frame;
 return layoutAttributes;
}

Moreover, the method layoutAttributesForItemAtIndexPath: never gets called implicitly. I even tried this:

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *attArray =[NSMutableArray arrayWithCapacity:attributeArrayOfAll.count];
for (NSInteger i =0; i< attributeArrayOfAll.count; i++) {
    UICollectionViewLayoutAttributes * attribute = (UICollectionViewLayoutAttributes*)[attributeArrayOfAll objectAtIndex:i];
    if(CGRectIntersectsRect(rect, attribute.frame)){
        [attArray insertObject:[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]] atIndex:i];
    }
}
return attArray;
}

But still the result is the same distorted set of cells on scrolling. I worked with 5 cells, first time it renders correctly, on scrolling away and then bringing it back in visible rect it gets distorted, if i scroll away again and bring it back in visible rect it renders correctly. However, when I do this with around 400 cells, once i scroll it never renders correctly. Even on reloading collection view, The cells gets distort. Please help.

Shivam Mishra
  • 137
  • 1
  • 12

2 Answers2

3

Your layoutAttributesForItemAtIndexPath: method is not setting any properties of the layoutAttributes object before returning it. It needs to set frame (or center and size).

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
0

So finally managed a workaround!!! dequeue each cell with an unique Cell Identifier in cellForRow:

[self.summaryView registerClass:[BFSSummaryViewCell class] forCellWithReuseIdentifier:[NSString stringWithFormat:@"%@%d",CellIdentifier,indexPath.row]];
UICollectionViewCell *collectionCell = [collectionView dequeueReusableCellWithReuseIdentifier:[NSString stringWithFormat:@"%@%d",CellIdentifier,indexPath.row] forIndexPath:indexPath];

These two lines inside cellForRow worked for me, however with my collection view having around 1000 cells it increases the size of my application considerably. Lets hope apple fixes this bug asap.

Shivam Mishra
  • 137
  • 1
  • 12
  • 3
    Sorry, but this is a terrible way to solve this problem. The architecture of the UICollectionView class is set up so that you get reuse of cells. If you have a different cell class for each possible cell, you're just making things difficult for yourself. Try to solve the actual problem you're having, without using this hack. – buildsucceeded Jul 08 '13 at 10:35
  • @buildsucceeded I know it is a sad and bad way out. But I found an open radar for this problem, and had no other choice in spite of trying almost everything. If you can share a better solution you are more than welcome. Believe me, my collection view has become very grumpy on scrolling. I am having nightmares!!!! :) – Shivam Mishra Jul 10 '13 at 06:01
  • It looks like you're trying to do too much management of cells yourself, even without this 'workaround' of having (shudder) one class per cell. Where are you calling cellForItemAtIndexPath and dequeuing? If I were you, I would start over in a brand new project and make sure the dequeuing works without messing with the attributes before I started overriding any of the methods you're using. – buildsucceeded Jul 10 '13 at 09:27
  • 1
    @buildsucceeded the above code only shows class for my custom layout. And you need to override the above methods if you wanna create your own layout. The cellForItemAtIndexPath: is implemented in my collection view controller class, where i am dequeuing(anyways ,you cannot proceed without dequeuing in collection view). As I said, I found an open radar for the above problem, and thus this crude workaround. Yes The cell management can be improved. but that is not the issue here. – Shivam Mishra Jul 11 '13 at 05:27