jo3birdtalk
jo3birdtalk

Reputation: 616

How to display 3 cell per row UICollectionView

As per the header, I'm using UICollectionView to display images. I need to display 3 cells per row, something like how Instagram does it.

Because there are many screen sizes, I'm getting the width of the iPhone screen, then divide it by 3. However, it does not show as per what I need it to be.

Here are my codes inside the viewDidLoad() method:

private let leftAndRightPaddings: CGFloat = 8.0
private let numberOfItemsPerRow: CGFloat = 3.0
private let heightAdjustment: CGFloat = 30.0    

let bounds = UIScreen.mainScreen().bounds
let width = (bounds.size.width - leftAndRightPaddings) / numberOfItemsPerRow
let layout = userDetailCollection.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSizeMake(width, width)

enter image description here

Upvotes: 0

Views: 5422

Answers (3)

Rohit Pradhan
Rohit Pradhan

Reputation: 3875

Replace this line

let width = (bounds.size.width - leftAndRightPaddings) / numberOfItemsPerRow

with

let width = (bounds.size.width - leftAndRightPaddings*4) / numberOfItemsPerRow

As you are not considering spacing between two items & Right insets spacing therefore it is not adjusting in the screen.

private let leftAndRightPaddings: CGFloat = 15.0
private let numberOfItemsPerRow: CGFloat = 3.0

let bounds = UIScreen.mainScreen().bounds
let width = (bounds.size.width - leftAndRightPaddings*(numberOfItemsPerRow+1)) / numberOfItemsPerRow
let layout = userDetailCollection.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSizeMake(width, width)   

Try this code

Upvotes: 4

HeTzi
HeTzi

Reputation: 916

overriding UICollectionViewLayout will let you much more flexibility in creating collectionViews. here is a snippet for YourOwnCollectionViewLayout : UICollectionViewLayout:

- (NSInteger)itemWidth {
    return (self.collectionView.bounds.size.width - (HORIZONTAL_PAD * (NUMBER_OF_ITEMS_PER_ROW+1))) / NUMBER_OF_ITEMS_PER_ROW; // pad from each side + pad in the middle
}

- (NSInteger)itemHeight {
    return self.itemWidth; // or something else
}

- (NSString *)keyForIndexPath:(NSIndexPath *)indexPath {
    NSString *retVal = [NSString stringWithFormat:@"%ld-%ld", (long)indexPath.section, (long)indexPath.row];
    return retVal;
}

- (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat itemWidth  = [self itemWidth];
    CGFloat itemHeight = [self itemHeight];

    CGFloat originX = HORIZONTAL_PAD + ((indexPath.row % NUMBER_OF_ITEMS_PER_ROW)*(HORIZONTAL_PAD + itemWidth));
    CGFloat originY = VERTICAL_PAD + (floorf(indexPath.row/NUMBER_OF_ITEMS_PER_ROW)*(VERTICAL_PAD + itemHeight));

    return CGRectMake(originX, originY, itemWidth, itemHeight);
}

- (void)prepareLayout {
    NSMutableDictionary *newLayoutInfo  = [NSMutableDictionary dictionary];
    NSMutableDictionary *cellLayoutInfo = [NSMutableDictionary dictionary];

    NSInteger sectionCount = [self.collectionView numberOfSections];
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];

    for (NSInteger section = 0; section < sectionCount; section++) {
        NSInteger itemCount = [self.collectionView numberOfItemsInSection:section];

        for (NSInteger item = 0; item < itemCount; item++) {
            indexPath = [NSIndexPath indexPathForItem:item inSection:section];

            UICollectionViewLayoutAttributes *itemAttributes =
            [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
            itemAttributes.frame = [self frameForItemAtIndexPath:indexPath];

            NSString *key        = [self keyForIndexPath:indexPath];
            cellLayoutInfo[key]  = itemAttributes;
        }
    }

    newLayoutInfo[@"CellKind"] = cellLayoutInfo;
    self.layoutInfo            = newLayoutInfo;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    NSString *key = [self keyForIndexPath:indexPath];
    UICollectionViewLayoutAttributes *retVal = self.layoutInfo[@"CellKind"][key];
    return retVal;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSMutableArray *allAttributes = [NSMutableArray arrayWithCapacity:self.layoutInfo.count];

    [self.layoutInfo enumerateKeysAndObjectsUsingBlock:^(NSString *elementIdentifier,
                                                         NSDictionary *elementsInfo,
                                                         BOOL *stop) {
        [elementsInfo enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *indexPath,
                                                          UICollectionViewLayoutAttributes *attributes,
                                                          BOOL *innerStop) {

            if (CGRectIntersectsRect(rect, attributes.frame)) {
                [allAttributes addObject:attributes];
            }
        }];
    }];

    return allAttributes;
}

- (CGSize)collectionViewContentSize {
    return CGSizeMake(self.collectionView.bounds.size.width, floorf([self.collectionView numberOfItemsInSection:0]/NUMBER_OF_ITEMS_PER_ROW) * (self.itemHeight + VERTICAL_PAD) + VERTICAL_PAD);
}

in your mainView add: [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:[[YourOwnCollectionViewLayout alloc] init]]; and you're DONE!

Upvotes: 2

Varun
Varun

Reputation: 759

You are not considering the sectionInset and the interItemSpacing. It has some default values which pushes the cells(gives padding). Either you can set the interItemSpacing to 0 and sectionInset to UIEdgeInsetsZero or you have to consider their values during calculation of the cellWidth.

Override these protocol methods for setting the size, insets and interItem spacing

optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize

optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets

optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat

optional public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat

Upvotes: 0

Related Questions