UICollectionViewFlowLayout with vertical scrolling misplaces elements in 1st col

Originator:alex.sporn
Number:rdar://12433891 Date Originated:04-Oct-2012
Status:Open Resolved:
Product:iPhone SDK Product Version:6.0 (10A403)
Classification:UI/Usability Reproducible:Always
 
Summary:
--------
When using an UICollectionViewFlowLayout with a combination of itemSize, minimumInteritemSpacing and sectionInset that exactly matches the width of the UICollectionView and a default vertical scrollDirection the layout misplaces the items in the first column. The items are instead placed on the border of the previous row as an additional column.

Steps to Reproduce:
-----------------
Create a simple UICollectionView with UICollectionViewFlowLayout with the following properties and enough cells to make the collectionView scroll. Scroll down and back up the collectionView to see the misplaced cells.

UICollectionView properties:
collectionView.bounds = (0.0f, 0.0f, 320.0f, 460.0f)

UICollectionViewFlowLayout properties:
scrollDirection = UICollectionViewScrollDirectionVertical
itemSize = CGSizeMake(90.0f, 110.0f)
minimumInteritemSpacing = 10.0f
sectionInset = UIEdgeInsetsMake(15.0f, 15.0f, 15.0f, 15.0f);

This can be reproduced with every combination of itemSize, minimumInteritemSpacing and sectionInset for a multi column layout that exactly matches the width of the collectionView.

Expected Results:
--------------
A collectionView layout with 3 columns that scrolls vertically

Actual Results:
------------
Sometimes the item in the first column is misplaced as a fourth column of the previous row.

Notes:
------
A sample project and a screenshot are attached to this radar. Compile this project and simply scroll down & up multiple times with different speeds.

Comments

used andrew.d.morrow type of solution to work around. Would really like to know if there is a more legitimate fix to this issue.

By jenkins5824 at April 3, 2013, 4:44 p.m. (reply...)

also ran into the same issue, andrew's solution also worked for me.

I've seen the same issue, Andrew's solution worked for me.

I also had this bug. mayoff's fix didn't quite do the trick, so here's my change:

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *unfilteredPoses = [super layoutAttributesForElementsInRect:rect];
    id filteredPoses[unfilteredPoses.count];
    NSUInteger filteredPosesCount = 0;
    for (UICollectionViewLayoutAttributes *pose in unfilteredPoses) {
        CGRect frame = pose.frame;
        if (frame.origin.x + frame.size.width <= rect.size.width) { // I changed this line
            filteredPoses[filteredPosesCount++] = pose;
        }
    }
    return [NSArray arrayWithObjects:filteredPoses count:filteredPosesCount];
}
By andrew.d.morrow at Nov. 20, 2012, 12:04 a.m. (reply...)

I've run into this bug too. It appears that -[UICollectionViewFlowLayout layoutAttributesForElementsInRect:] returns two layout attributes objects for the items that should be in the leftmost column. One of the objects correctly puts the item in the leftmost column and the other object incorrectly puts the item in the out-of-bounds column on the right.

To work around it, I subclassed UICollectionViewFlowLayout. Here's the entire implementation of my subclass:

@implementation BugFixFlowLayout

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *unfilteredPoses = [super layoutAttributesForElementsInRect:rect];
    id filteredPoses[unfilteredPoses.count];
    NSUInteger filteredPosesCount = 0;
    for (UICollectionViewLayoutAttributes *pose in unfilteredPoses) {
        if (CGRectIntersectsRect(rect, pose.frame)) {
            filteredPoses[filteredPosesCount++] = pose;
        }
    }
    return [NSArray arrayWithObjects:filteredPoses count:filteredPosesCount];
}

@end

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!