ylliX - Online Advertising Network Tutorial: Custom UITable section header using Interface Builder - Yet Another Programmer's Blog

Tutorial: Custom UITable section header using Interface Builder

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”:
Zrzut ekranu 2015-01-11 o 10.09.37

Enter name whatever you want:
Zrzut ekranu 2015-01-11 o 10.10.26

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):

Zrzut ekranu 2015-01-11 o 10.59.04

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:

Zrzut ekranu 2015-01-11 o 10.20.15

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:

Zrzut ekranu 2015-01-11 o 10.23.41

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:

Zrzut ekranu 2015-01-11 o 10.31.41

and second one:

Zrzut ekranu 2015-01-11 o 10.32.32

So now you file browser will look like this:

Zrzut ekranu 2015-01-11 o 10.33.21

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:

Zrzut ekranu 2015-01-11 o 10.48.10

and for section header:

Zrzut ekranu 2015-01-11 o 10.48.44

So now your row cell should be connected to its var:

Zrzut ekranu 2015-01-11 o 10.50.34

So should be section header cell:
Zrzut ekranu 2015-01-11 o 10.51.27Now 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:

Zrzut ekranu 2015-01-11 o 10.59.57

Feel free to play with interface assets to achieve look you want. If you want, you can grab whole project on GitHub here.

Leave a Reply