Creating a grid view in iOS
Creating a table in iOS is easy, but there are times when you need a grid instead of a simple table. I’ll walk you through the steps for making a grid. In this example, I want a table that has three cells per row. The final product will look like this:
GridTableViewCell
The core piece in your grid is a custom UITableViewCell. Start off by making a new class derived from UITableViewCell. I called mine GridTableViewCell. I want my grid to have 3 cells per row, so my interface is going to look like this:
@interface GridTableViewCell : UITableViewCell { UIColor *lineColor; BOOL topCell; UILabel *cell1; UILabel *cell2; UILabel *cell3; } @property (nonatomic, retain) UIColor* lineColor; @property (nonatomic) BOOL topCell; @property (readonly) UILabel* cell1; @property (readonly) UILabel* cell2; @property (readonly) UILabel* cell3; @end |
The UILabels are created in initWithStyle and are sized to fit within each cell. lineColor is self-explanatory. topCell is a bit trickier. Our line drawing code (see below) draws the vertical lines and a horizontal line at the bottom of the cell. However, this leaves the top cell in the table without a line on top. To work around this, we add a flag to the cell to indicate whether the cell is the top cell. If it is, draw a line on the top of the cell.
We do our line drawing in drawRect. In the implementation for GridTableViewCell I have overridden the drawRect method and added the line drawing code. Here is what it looks like:
#define cell1Width 80 #define cell2Width 80 #define cellHeight 44 - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetStrokeColorWithColor(context, lineColor.CGColor); // CGContextSetLineWidth: The default line width is 1 unit. When stroked, the line straddles the path, with half of the total width on either side. // Therefore, a 1 pixel vertical line will not draw crisply unless it is offest by 0.5. This problem does not seem to affect horizontal lines. CGContextSetLineWidth(context, 1.0); // Add the vertical lines CGContextMoveToPoint(context, cell1Width+0.5, 0); CGContextAddLineToPoint(context, cell1Width+0.5, rect.size.height); CGContextMoveToPoint(context, cell1Width+cell2Width+0.5, 0); CGContextAddLineToPoint(context, cell1Width+cell2Width+0.5, rect.size.height); // Add bottom line CGContextMoveToPoint(context, 0, rect.size.height); CGContextAddLineToPoint(context, rect.size.width, rect.size.height-0.5); // If this is the topmost cell in the table, draw the line on top if (topCell) { CGContextMoveToPoint(context, 0, 0); CGContextAddLineToPoint(context, rect.size.width, 0); } // Draw the lines CGContextStrokePath(context); } |
The UILabels are created in the cell’s init function. The code to create the labels looks like this:
cell1 = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, cell1Width, cellHeight)]; cell1.textAlignment = UITextAlignmentCenter; cell1.backgroundColor = [UIColor clearColor]; // Important to set or lines will not appear [self addSubview:cell1]; |
The final important task to handle in the cell is to redraw the cell when its topCell state changes. Since we are reusing cells in our table view, the cell does not always get redrawn and we can end up with an extra top line where there should not be one. The remedy to this problem is straightforward – override the setter function for the topCell property.
- (void)setTopCell:(BOOL)newTopCell { topCell = newTopCell; [self setNeedsDisplay]; } |
UITableView
Now that we have our custom table cell, let’s use it in our TableView. All the magic happens in cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; GridTableViewCell *cell = (GridTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[GridTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; cell.lineColor = [UIColor blackColor]; } // Since we are drawing the lines ourself, we need to know which cell is the top cell in the table so that // we can draw the line on the top if (indexPath.row == 0) cell.topCell = YES; else cell.topCell = NO; // Configure the cell. cell.cell1.text = [NSString stringWithFormat:@"%i", indexPath.row]; cell.cell2.text = [NSString stringWithFormat:@"%i", indexPath.row]; cell.cell3.text = @"Sample text"; return cell; } |
The final task is to turn off the table view’s default lines. This is done in viewDidLoad in our view controller:
- (void)viewDidLoad { [super viewDidLoad]; // Turn off the tableView's default lines because we are drawing them all ourself self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; } |
Wrap-Up
That’s all there is to it for making a grid view. I have posted a demo project on GitHub – GridTableView.




































