Search code examples
iosios6uicollectionviewuicollectionviewlayout

Display images in a UICollectionView - how to achieve fixed vertical spacing between images?


I am using a UICollectionView to present a grid of images in an iPhone app (iOS6).

I am using vertical scrolling for the UICollectionView, and the images all have fixed width and varying height. The width of the images are set so that on an iPhone, it displays 3 columns of images. This works ok, and I get the images presented in a grid view.

However, since my images have varying height, the vertical spacing between images in a column varies and this doesn't look very good, as you can see in the following image (a mockup made in HTML):

Image showing how the images are currently laid out

I would instead like to achieve a more fluid flow, where the vertical spacing between images in a column are the same. The following mockup shows how I would like it to work:

Example of how I would like the flow of images to work

Any ideas of how to solve this?

Also, as a bonus question, does anyone know a way to solve the same problem if the app was not built for iOS6 (since UICollectionView is only available in iOS6). Either by using a 3rd party component or by solving it with standard iOS controls.


Solution

  • Subclass UICollectionViewFlowLayout and in that class add these methods. (Note this assumes a vertical orientation, and it skips the first line, and it is a constant 10 pixels between them. See: how do you determine spacing between cells in UICollectionView flowLayout if you need the horizontal version

    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray* arr = [super layoutAttributesForElementsInRect:rect];
    for (UICollectionViewLayoutAttributes* atts in arr) {
        if (nil == atts.representedElementKind) {
            NSIndexPath* ip = atts.indexPath;
            atts.frame = [self layoutAttributesForItemAtIndexPath:ip].frame;
        }
    }
    return arr;
    }
    
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes* atts =
    [super layoutAttributesForItemAtIndexPath:indexPath];
    
    if (indexPath.item == 0 || indexPath.item == 1) // degenerate case 1, first item of section
        return atts;
    
    NSIndexPath* ipPrev =
    [NSIndexPath indexPathForItem:indexPath.item-2 inSection:indexPath.section];
    
    CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
    CGFloat rightPrev = fPrev.origin.y + fPrev.size.height + 10;
    if (atts.frame.origin.y <= rightPrev) // degenerate case 2, first item of line
        return atts;
    
    CGRect f = atts.frame;
    f.origin.y = rightPrev;
    atts.frame = f;
    return atts;
    }