-->

UICollectionView - order cells horizontally

2019-02-18 10:19发布

问题:

So basically my problem is that my uicollectionview's cells are ordered from top to bottom, rather than from left to right.

This is what it looks like -
[1][4][7]
[2][5][8]
[3][6][9]

This is what i want -
[1][2][3]
[4][5][6]
[7][8][9]

Another problem is when i scroll horizontally instead of moving the page a full 320points. It only moves enough to fit the next cell in the view.

this is what it looks like -
    [2][3][10]
    [5][6][  ]
    [8][9][  ]

this is what i want -
    [10][ ][ ]
    [  ][ ][ ]
    [  ][ ][ ]

I was hoping rendering it horizontally would fix it though. I'm still new to ios so please show me how to do it, all the tuts i searched are not for my exact problem or is outdated.

回答1:

This is my solution, hope it helpful:

CELLS_PER_ROW = 4;
CELLS_PER_COLUMN = 5;
CELLS_PER_PAGE = CELLS_PER_ROW * CELLS_PER_COLUMN;

UICollectionViewFlowLayout* flowLayout = (UICollectionViewFlowLayout*)collectionView.collectionViewLayout;
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flowLayout.itemSize = new CGSize (size.width / CELLS_PER_ROW - delta, size.height / CELLS_PER_COLUMN - delta);
flowLayout.minimumInteritemSpacing = ..;
flowLayout.minimumLineSpacing = ..;
..

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSInteger index = indexPath.row;
    NSInteger page = index / CELLS_PER_PAGE;
    NSInteger indexInPage = index - page * CELLS_PER_PAGE;
    NSInteger row = indexInPage % CELLS_PER_COLUMN;
    NSInteger column = indexInPage / CELLS_PER_COLUMN;

    NSInteger dataIndex = row * CELLS_PER_ROW + column + page * CELLS_PER_PAGE;

    id cellData = _data[dataIndex];
    ...
}


回答2:

1) If you are using horizontal scrolling in collection view, the order will be like what you have

[1][4][7]
[2][5][8]
[3][6][9]

If you want this order to change, you have to use vertical scrolling.

2) If you want collection view to scroll a full page, enable paging from IB or

colloctionView.pagingEnabled = YES;


回答3:

You have to implement a CustomLayout to solve this problem. Here is my solution:

/*
    This is what it looks like -
    [1][3] [5][7]
    [2][4] [6][8]

    This is what i want -
    [1][2] [5][6]
    [3][4] [7][8]
*/

#import "AWCustomFlowLayout.h"

CGFloat const kCellWidth = 130.0;
CGFloat const kCellHeight = 170.0;
CGFloat const kCellLineSpacing = 20.0;
CGFloat const kCellInteritemSpacing = 10.0;

@implementation AWCustomFlowLayout

- (instancetype)init {
    self = [super init];
    if (self) {
        self.minimumLineSpacing = kCellLineSpacing;
        self.minimumInteritemSpacing = kCellInteritemSpacing;
        self.itemSize = CGSizeMake(kCellWidth, kCellHeight);
        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        self.sectionInset = UIEdgeInsetsMake(0, kCellLineSpacing, 0, 0);
    }

    return self;
}

- (UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    UICollectionViewLayoutAttributes *attribute = [super layoutAttributesForItemAtIndexPath:indexPath];
    [self modifyLayoutAttribute:attribute];
    return attribute;
}

- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect{
    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
    for(UICollectionViewLayoutAttributes *attribute in attributes){
        [self modifyLayoutAttribute:attribute];
    }

    return attributes;
}


- (void)modifyLayoutAttribute:(UICollectionViewLayoutAttributes*)attribute{
    CGRect frame = attribute.frame;

    NSInteger cellX = attribute.frame.origin.x;
    NSInteger cellY = attribute.frame.origin.y;
    NSInteger cellWidth = attribute.frame.size.width;
    NSInteger const firstColumnX = kCellLineSpacing;
    NSInteger const secondColumnX = kCellWidth + kCellLineSpacing*2;
    NSInteger const firstRowY = 0;
    NSInteger const secondRowY = kCellHeight + kCellInteritemSpacing;

    BOOL isFirstColumn = cellX % firstColumnX == 0;
    BOOL isSecondColumn = (cellX+cellWidth) % (secondColumnX+cellWidth) == 0;
    BOOL isFirstRow = cellY == firstRowY;
    BOOL isSecondRow = cellY == secondRowY;

    if (isFirstColumn && isSecondRow) {
        frame.origin.x += secondColumnX-firstColumnX;
        frame.origin.y = firstRowY;
    }
    else if (isSecondColumn && isFirstRow) {
        frame.origin.x -= secondColumnX-firstColumnX;
        frame.origin.y = secondRowY;
    }

    attribute.frame = frame;
}

@end


回答4:

Assuming that you are using a section for each "page", have a look at this picture, which describes how the cells are build:

so instead of [0..11] we want this order: [0,3,6,9,1,4,7,10,2,5,8,11].

If you look further at the second array, you can rebuild this one using the number of columns and number of rows of your pages:

let columns: Int = 4
let rows: Int = 3

var correctRowOrder = [Int]()

for index in 0..<columns {
    let array = Array(0..<rows).map {$0*columns}.map {$0+index}
    correctRowOrder += array
}
    // You can use this one within the cellForItemAt method provided by the collectionview!
    let correctIndexPath = correctRowOrder[indexPath.row]

Remember to use sections for this solution!