iOS custom UITableViewCell example using xib file

iOS custom UITableViewCell example using xib file   The UITableViewCell class defines the attributes and behavior of the cells that appear in UITableView objects. The iOS SDK comes with some predefined cell styles for your most common needs but what if you need a different layout for your table row data. Well you can easily extend the UITableViewCell class to create a new custom class and initialize that with your custom xib file.

In this example we are going to display a list of countries from an array. To create our custom UITableViewCell first we need to create an empty xib file and then add Table View Cell from the list of objects. Next you can customize the cell view such as increase the dimensions, add components such as Labels, Buttons, etc. After that create a custom class extending the UITableViewCell class and then connect the labels from the xib file using IBOutlet.

If you are interested in programmatically creating a custom cell for the Table view click here.

Create a new Interface Builder file for the cell view

Create a new File(Cmd+N), then from the category select User Interface and from right section select empty, then click next to continue. Choose iPhone as the device and click next. Give the file a name, for this example we chose CountryCell.xib and then click create.
iOS custom UITableViewCell user interface 1
iOS custom UITableViewCell user interface 2

Next from the Object Library, select Table View Cell and drag it to the design area. Add a few labels and a button as shown in the picture below. We added four labels to display for country name, code, continent, population and a custom button to interact with the cell view when the user taps on it. Using the Attributes Inspector you can customize your labels such as make the country name as bold.
iOS custom UITableViewCell label and button

Next we have to create our custom CountryCell object extending the UITableViewCell class. Again create a new file(Cmd+N) and this time choose Cocoa Touch from the category and Objective-C class from the right section, click next to continue. Give the class name as CountryCell and subclass of UITableViewCell, click next choose folder and then create the files. This should now generate two files in your project folder named CountryCell.h and CountryCell.m
iOS custom cell using subclass as UITableViewCell

At this point open your xib file and the CountryCell interface file side by side in the editor and make the IBOutlet connections. You can select a label, then press on both Control+mouse and drag the mouse over to the interface file, it will prompt you to create a connection. I am not going to go into the details how to make these connections as they are same as if you were to create any other views while working with xib files. Do this for all your labels and the button. See images below for help

We are almost done with the setup here. Select your view in Objects list and then in the identity inspecter change the custom class to CountryCell. At this point your custom CountryCell class will look like this

Interface file for the custom cell - CountryCell.h

#import <UIKit/UIKit.h>

@interface CountryCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UILabel *countryLabel;
@property (weak, nonatomic) IBOutlet UILabel *codeLabel;
@property (weak, nonatomic) IBOutlet UILabel *continentLabel;
@property (weak, nonatomic) IBOutlet UILabel *populationLabel;
@property (weak, nonatomic) IBOutlet UIButton *detailInfoButton;

@end

Implementation file for the custom cell - CountryCell.m

#import "CountryCell.h"

@implementation CountryCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end

Interface file for the country object - Country.h

#import <Foundation/Foundation.h>

@interface Country : NSObject

@property (nonatomic, strong) NSString *code;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *continent;
@property (nonatomic, strong) NSNumber *population;

-(id)initWithCode:(NSString *)code_
             name:(NSString *)name_
        continent:(NSString *)continent_
       population:(NSNumber *)population_;

@end

Implementation file for the country object - Country.m

#import "Country.h"

@implementation Country

@synthesize code;
@synthesize name;
@synthesize continent;
@synthesize population;


-(id)initWithCode:(NSString *)code_
             name:(NSString *)name_
        continent:(NSString *)continent_
       population:(NSNumber *)population_
{
    self = [super init];
    if (self) {
        self.code = code_;
        self.name = name_;
        self.continent = continent_;
        self.population = population_;
    }
    return self;
}

@end

Interface file for the app delegate - TableViewCustomCellAppDelegate.h

#import <UIKit/UIKit.h>

@class TableViewCustomCellViewController;

@interface TableViewCustomCellAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) TableViewCustomCellViewController *viewController;

@end

Implementation file for the app delegate - TableViewCustomCellAppDelegate.m

#import "TableViewCustomCellAppDelegate.h"

#import "TableViewCustomCellViewController.h"

@implementation TableViewCustomCellAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //initialize the screen
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    //initialize your view controller
    self.viewController = [[TableViewCustomCellViewController alloc]            initWithNibName:@"TableViewCustomCellViewController" bundle:nil];
    
    //make the new view controller as your root view controller
    self.window.rootViewController = self.viewController;
    //set background color and make your window visible
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;

}

@end

Interface file for the Table view - TableViewCustomCellViewController.h

#import <UIKit/UIKit.h>
#import "Country.h"
#import "CountryCell.h"

@interface TableViewCustomCellViewController : UIViewController
                                                <UITableViewDelegate,UITableViewDataSource>

@property (nonatomic, strong) UITableView *myTableView;
@property (nonatomic, strong) NSMutableArray *countryList;

@end

Implementation file for the Table view - TableViewCustomCellViewController.m

#import "TableViewCustomCellViewController.h"

@interface TableViewCustomCellViewController ()

@end

@implementation TableViewCustomCellViewController

@synthesize myTableView;
@synthesize countryList;

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    
    //intialize our data to be displayed in the table view
    [self loadCountryData];
    
    //create the table view with a given style
    self.myTableView = [[UITableView alloc] initWithFrame:self.view.bounds
                                                    style:UITableViewStyleGrouped];
    
    //set the table view delegate to the current so we can listen for events
    self.myTableView.delegate = self;
    //set the datasource for the table view to the current object
    self.myTableView.dataSource = self;
    
    //make sure our table view resizes correctly
    self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
    UIViewAutoresizingFlexibleHeight;
    
    //add the table view to the main view
    [self.view addSubview:self.myTableView];
    
}

//Asks the delegate for a view object to display in the header of the specified
//section of the table view, display the continent name in the header view
- (UIView *) tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section{
    
    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,
                                                                  tableView.bounds.size.width, 30)];
    headerView.backgroundColor = [UIColor clearColor];
    
    if ([tableView isEqual:self.myTableView]){
        UILabel *result = [[UILabel alloc]
                           initWithFrame:CGRectMake(12, 0,
                                                    tableView.bounds.size.width, 30)];
        result.font = [UIFont boldSystemFontOfSize:16.0f];
        result.text = [NSString stringWithFormat:@"%@ :", @"List of Countries"];
        result.backgroundColor = [UIColor clearColor];
        [headerView addSubview:result];
    }
    return headerView;
    
}

//asks the delegate for the height to use for the header of a particular section
- (CGFloat) tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section{
    
    CGFloat result = 0.0f;
    if ([tableView isEqual:self.myTableView]){
        result = 35.0f;
    }
    return result;
}


//asks the data source to return the number of rows in a given section of a table view
//we are returning the number of countries in a given continent
- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section{
    
    NSLog(@"%@",@"Called number of Rows in a Section");
    NSInteger numberOfRows = 0;
    
    if ([tableView isEqual:self.myTableView]){
        numberOfRows = self.countryList.count;
    }
    return numberOfRows;
}


//asks the data source for a cell to insert in a particular location of the table view
- (UITableViewCell *) tableView:(UITableView *)tableView
          cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    NSLog(@"%@",@"Render cell at a given Index Path Section and Row");
    CountryCell *myCellView = nil;
    
    if ([tableView isEqual:self.myTableView]){
        
        static NSString *TableViewCellIdentifier = @"CountryCell";
        
        //this method dequeues an existing cell if one is available or creates a new one
        //if no cell is available for reuse, this method returns nil
        myCellView = [tableView dequeueReusableCellWithIdentifier:TableViewCellIdentifier];
        if (myCellView == nil){
            //initialize the cell view from the xib file
            NSArray *nibs = [[NSBundle mainBundle] loadNibNamed:@"CountryCell"
                                                          owner:self options:nil];
            myCellView = (CountryCell *)[nibs objectAtIndex:0];
        }
        
        Country *country = [[Country alloc] init];
        country = [self.countryList objectAtIndex:indexPath.row];
        
        //populate data from your country object to table view cell
        myCellView.countryLabel.text = [NSString stringWithFormat:@"Name: %@",
                                        country.name];
        myCellView.codeLabel.text = [NSString stringWithFormat:@"Code: %@",
                                     country.code];
        myCellView.continentLabel.text = [NSString stringWithFormat:@"Continent: %@",
                                          country.continent];
        myCellView.populationLabel.text = [NSString stringWithFormat:@"Population: %@",
                                           country.population];
        [myCellView.detailInfoButton addTarget:self action:@selector(detailInfo:)
                              forControlEvents:UIControlEventTouchUpInside];
        
    }
    return myCellView;
}

- (void) detailInfo:(UIButton *)sender {
    
    CountryCell *ownerCell = (CountryCell *)[[sender superview] superview];
    NSIndexPath *indexPath = [self.myTableView indexPathForCell:ownerCell];
    
    Country *country = [[Country alloc] init];
    country = [self.countryList objectAtIndex:indexPath.row];
    NSLog(@"Country is %i %@", indexPath.row, country.name);
    
}

- (CGFloat) tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    CGFloat result = 20.0f;
    if ([tableView isEqual:self.myTableView]){
        result = 100.0f;
    }
    return result;
    
}


//create mutable array to hold list of countries that will be displayed
- (void) loadCountryData {
    
    NSMutableArray *array = [[NSMutableArray alloc] init];
    self.countryList = array;
    
    Country *country = [[Country alloc] initWithCode:@"USA"
                                                name:@"United States"
                                           continent:@"North America"
                                          population:[[NSNumber alloc] initWithInt:989898]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"CAN"
                                       name:@"Canada"
                                  continent:@"North America"
                                 population:[[NSNumber alloc] initWithInt:979797]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"MXN"
                                       name:@"Mexico"
                                  continent:@"North America"
                                 population:[[NSNumber alloc] initWithInt:969696]];
    [countryList addObject:country];
    
    country = [[Country alloc] initWithCode:@"CHN"
                                       name:@"China"
                                  continent:@"Asia"
                                 population:[[NSNumber alloc] initWithInt:959595]];
    [countryList addObject:country];
    country = [[Country alloc] initWithCode:@"AFG"
                                       name:@"Afghanistan"
                                  continent:@"Asia"
                                 population:[[NSNumber alloc] initWithInt:939393]];
    [countryList addObject:country];
    
}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end