I saw a lot of tutorials about custom header/footer, or even custom section header, but they were creating controls programatically, in this tutorial I want to show how easy is to use Interface Builder to achive same result.
So start with creating new XCode project:
Choose “Single View Application”:
And we can start finally. So using Interface Builder create UITable and two custom cells, one for table row, one for section header, also add one UILabel in each (so we can display something):
If your view looks like above – you’re on good way. Now we need to give our cells a reusable identifier – to get them later:
As you can see, my row cell has identifier “tableitem” and my header cell has “headeritem”. So let’s connect assets to header file ViewController.h:
@interface ViewController : UIViewController { __weak IBOutlet UITableView *table; } @end
and after right-click on table you should have:
Now we need to add UITableViewDataSource and UITableViewDelegate and place for your data, still in ViewController.h:
@interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate> { __weak IBOutlet UITableView *table; NSMutableArray* tableData; } @end
Then open ViewController.m and add some code to make it look like this:
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; tableData = [[NSMutableArray alloc] init]; [tableData addObject:@[@{@"key": @"1", @"label": @"item 1.1"}, @{@"key": @"1", @"label": @"item 1.2"}, @{@"key": @"3", @"label": @"item 1.3"}] ]; [tableData addObject:@[@{@"key": @"1", @"label": @"item 2.1"}, @{@"key": @"2", @"label": @"item 2.2"}, @{@"key": @"3", @"label": @"item 2.3"}, @{@"key": @"4", @"label": @"item 2.4"}] ]; table.delegate = self; table.dataSource = self; [table reloadData]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [tableData count]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[tableData objectAtIndex:section] count]; } -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 90.0; } @end
As you can see we don’t have cellForRowAtIndexPath and viewForHeaderInSection implemented yet, its only some basic code. There is a strange number in heightForHeaderInSection function, it should be your section header height you set in Interface Builder. If value will be different, your header will have too much space or view will be cut.
Now we need to extend UITableViewCell twice – first for table row, second for section header. So add new file:
and second one:
So now you file browser will look like this:
Now connect you labels to your new classes, you RowCell.h should look like this:
@interface RowCell : UITableViewCell @property (weak, nonatomic) IBOutlet UILabel *lblRowData; @end
And SectionHeaderCell.h like this:
@interface SectionHeaderCell : UITableViewCell @property (weak, nonatomic) IBOutlet UILabel *lblSectionData; @end
Next step is connection from Interface Builder to you vars, but first you need to assign your classes to proper cells, for table row:
and for section header:
So now your row cell should be connected to its var:
So should be section header cell:
Now we can add required imports to ViewController.m:
#import "RowCell.h" #import "SectionHeaderCell.h"
And add UITable delegate methods:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { SectionHeaderCell *cell = (SectionHeaderCell*)[tableView dequeueReusableCellWithIdentifier:@"headeritem"]; cell.lblSectionData.text = [NSString stringWithFormat:@"Header: %i", section]; return cell.contentView; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { RowCell *cell = (RowCell*)[tableView dequeueReusableCellWithIdentifier:@"tableitem"]; cell.lblRowData.text = [NSString stringWithFormat:@"%i.%i", indexPath.section, indexPath.row]; return cell; }
Some notes here, in cellForRowAtIndexPath as usual you get your cell via dequeueReusableCellWithIdentifier then you need to cast returned object to your RowCell class so instead of using viewWithTag method, you can just use cell.yourAsset. Very similar stuff goes in viewForHeaderInSection but, since this method has to return UIView, not UITableViewCell, we’re returning contentView property of UITableViewCell. Now compile and run your project and you should see:
Feel free to play with interface assets to achieve look you want. If you want, you can grab whole project on GitHub here.