How do I create a UICollectionView with column and row headers?

I want to create a UICollectionView that looks like this:

是的。这个。

It won't be scrollable or editable. I'm currently wondering how to write the layout for this. I'm guessing it won't be a subclass of UICollectionViewFlowLayout . I can think of a number of ways, but was curious if there was any "right" way. The cells will be animate-able.

Should each row or column be its own section?


I've done something like what you want with a subclass of UICollectionViewFlowLayout. It looks like this,

 @implementation MultpleLineLayout {
    NSInteger itemWidth;
    NSInteger itemHeight;
}

-(id)init {
    if (self = [super init]) {
        itemWidth = 80;
        itemHeight = 80;
    }
    return self;
}

-(CGSize)collectionViewContentSize {
    NSInteger xSize = [self.collectionView numberOfItemsInSection:0] * (itemWidth + 2); // the 2 is for spacing between cells.
    NSInteger ySize = [self.collectionView numberOfSections] * (itemHeight + 2);
    return CGSizeMake(xSize, ySize);
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path {
    UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];
    NSInteger xValue;
    attributes.size = CGSizeMake(itemWidth,itemHeight);
    xValue = itemWidth/2 + path.row * (itemWidth +2);
    NSInteger yValue = itemHeight + path.section * (itemHeight +2);
    attributes.center = CGPointMake(xValue, yValue);
    return attributes;
}


-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
    NSInteger minRow =  (rect.origin.x > 0)?  rect.origin.x/(itemWidth +2) : 0; // need to check because bounce gives negative values  for x.
    NSInteger maxRow = rect.size.width/(itemWidth +2) + minRow;
    NSMutableArray* attributes = [NSMutableArray array];
    for(NSInteger i=0 ; i < self.collectionView.numberOfSections; i++) {
        for (NSInteger j=minRow ; j < maxRow; j++) {
            NSIndexPath* indexPath = [NSIndexPath indexPathForItem:j inSection:i];
            [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
        }
    }
    return attributes;
}

The data is arranged as an array of arrays where each inner array supplies the data for one horizontal row. With the values I have in there now, and using your data as an example, the view looked like this,

在这里输入图像描述

This is the code I haven the view controller,

@interface ViewController ()
@property (strong,nonatomic) UICollectionView *collectionView;
@property (strong,nonatomic) NSArray *theData;
@end

@implementation ViewController

- (void)viewDidLoad {
    self.theData = @[@[@"",@"A",@"B",@"C"],@[@"1",@"115",@"127",@"132"],@[@"2",@"",@"",@"153"],@[@"3",@"",@"199",@""]];

    MultpleLineLayout *layout = [[MultpleLineLayout alloc] init];
    self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout];
    self.collectionView.dataSource = self;
    self.collectionView.delegate = self;
    layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    self.view.backgroundColor = [UIColor blackColor];
    [self.view addSubview:self.collectionView];
    [self.collectionView registerNib:[UINib nibWithNibName:@"CustomDataCell" bundle:nil] forCellWithReuseIdentifier:@"DataCell"];
}


- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section {
    return [self.theData[section] count];
}

- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView {
    return [self.theData count];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView  cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    DataCell *cell = [collectionView  dequeueReusableCellWithReuseIdentifier:@"DataCell" forIndexPath:indexPath];
    cell.label.text = self.theData[indexPath.section][indexPath.row];
    return cell;
}

You can do it with UICollectionViewFlowLayout but if you go that way you need to count carefully and get the padding (ie the top left, and other "empty" cells) right. If you miscount it's obvious because the flow ruins everything quickly and you will find your header cells halfway down your columns. (I have done a similar thing)

I only did it that way because of a fear of custom layouts - but in fact it is as easy as UITableView . If your layout does not scroll at all then yours will be particularly simple as your only real work will be calculating frame values for cells, to be returned in layoutAttributesForItemAtIndexPath . Since your whole view fits in the visible area, layoutAttributesForElementsInRect will mean you simply iterate through all the cells in the view. collectionViewContentSize will be the size of your view.

Looking at your sample picture you might find it convenient to organise your data as a dictionary of arrays, one per column. You can get a column array by name ("A", "B" etc.) and the position in the array corresponds to the value in the leftmost column, which you might name "index".

There are many more methods you can use but those are the basics, and will get your basic display up and running.

链接地址: http://www.djcxy.com/p/84164.html

上一篇: IOS:UICollectionView方向上奇怪的动画

下一篇: 如何用列和行标题创建UICollectionView?