2

I have subclassed flow layout and set it as my collectionViewLayout on my collection view.

Then I set up the layout as follows:

- (id) init
{
    if(self = [super init])
    {
        self.minimumInteritemSpacing = 11.0;
        self.scrollDirection = UICollectionViewScrollDirectionVertical;
        self.itemSize = CGSizeMake(64.0,32.0);
        self.minimumLineSpacing = 10.0;
        self.sectionInset = UIEdgeInsetsMake(11.0,95.0,11.0,11.0);

        return self;
    }
    return nil;
}

95 + 64 + 11 + 64 + 11 + 64 + 11 = 320 - i checked it. (thats one left inset, 3 cells, 2 spaces and one right inset)

I have 1 section, 72 items, and my cell for index path function:

- (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifierForCustomCell forIndexPath:indexPath];

    cell.mainLabel.text = [@(indexPath.item) stringValue];

    return cell;
}

The output is this:

screenshot

As you can see, there's just 2 cells per row. Furthermore, it is not displaying every 3rd cell.

I had a look at what flow layout's layout function was producing

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {

gives... console output

This is the first 3 layout attributes in the layoutAttributes [NSArray] and as you can see it has decided to only deem the first 2 and then the 4th item as visible for the rect (320 by 568). This has to be an error in collection view layout, doesn't it? The collection view fills the screen and is 320 wide. So since this is a line breaking layout, no items should be off screen.

With edge insets removed:

screenshot 2

It works as it is supposed to. But I would like to have section insets since I need to add some decoration views which need to be in the same scroll view while I need a much bigger lleft inset than right inset.

BYZZav
  • 1,344
  • 17
  • 30

2 Answers2

1

There is a bug in Apple's UICollectionViewFlowLayout where some cells are displayed out of bounds. These resources will help you to fix it (you have to create a subclass of UICollectionViewFlowLayout and override this method):

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
    NSMutableArray *newAttributes = [NSMutableArray arrayWithCapacity:attributes.count];
    for (UICollectionViewLayoutAttributes *attribute in attributes) {
        if ((attribute.representedElementCategory != UICollectionElementCategoryCell) || // always include everything that's not a cell
            ((attribute.frame.origin.x + attribute.frame.size.width <= (self.collectionViewContentSize.width - self.sectionInset.right)) &&
             (attribute.frame.origin.y + attribute.frame.size.height <= (self.collectionViewContentSize.height - self.sectionInset.bottom))))
        {
            [newAttributes addObject:attribute];
        }
    }
    return newAttributes;
}

Sources for the basis for this fix:

Community
  • 1
  • 1
Johannes Fahrenkrug
  • 38,500
  • 17
  • 113
  • 155
  • Unfortunately i already tried this. If im reading it correctly, this is remove 'extra' partially off-screen items from being drawn. My problem is that the function is just not including all the items that should be on-screen – BYZZav Jan 07 '14 at 20:49
  • No, try it again. This will fix your problem. I had exactly the same problem. The issue stems from the layout ignoring the insets in its calculation is certain cases. It then returns 2(!) layout attribute objects for a single cell, one of which is invalid. This code fixes that. – Johannes Fahrenkrug Jan 07 '14 at 20:56
  • My attributes array print out (above) is obtained by putting break points at the 'return newAttributes' line of that very function. There are 28 items in attributes and 28 items in newAttributes. If you think about...my problem is that [super layout...] is skipping out items at certain index paths (which should be displayed); how would a function which is actually filtering the attributes array meant to add those skipped index paths back in? – BYZZav Jan 07 '14 at 21:01
  • It works as its supposed to. It displays 4 items per row since 4 items = 256 and 3 spaces = 33 and 320 > (256 + 33) – BYZZav Jan 07 '14 at 21:21
  • i attached a screenshot if sectionInset is (11,0,11,0) – BYZZav Jan 07 '14 at 21:24
  • See this: http://stackoverflow.com/questions/13360975/uicollectionviews-cell-disappearing-ios It seems as if the bug occurs when the inset/spacing/width values perfectly add up to the width of the collection view. Try making the cells one pixel smaller or the remove a pixel from the insets and see if that helps. – Johannes Fahrenkrug Jan 07 '14 at 21:31
  • Yeah I tried that too, I tried changing the left and right to all sorts of values. For the moment im just changing it so it displays 3 per row and then manually changing all the x values to what I want. – BYZZav Jan 07 '14 at 21:42
1

Until someone works out whats going on and whether or not this is a bug, the method I am using to fix this currently is:

- (NSArray *)alterAttributes:(NSArray *)attributes
{
    for (UICollectionViewLayoutAttributes *attribute in attributes) {

        switch (attribute.indexPath.item % 3) {
            case 0:
                attribute.center = CGPointMake(CellX1,attribute.center.y);
                break;
            case 1:
                attribute.center = CGPointMake(CellX2,attribute.center.y);
                break;
            case 2:
                attribute.center = CGPointMake(CellX3,attribute.center.y);
                break;

            default:
                break;
        }
    }
    return attributes;
}

Manually changing the x coordinates in layoutAttributesForElementsInRect - not really a satisfying solution.

BYZZav
  • 1,344
  • 17
  • 30