iPhone SDK Articles

Thursday, August 14, 2008

Table View Tutorial - TableView Cell Columns



IMPORTANT:
The following tutorial has been deprecated and should no longer be used for any purposes. To learn more on how to use the UITableView click here



Welcome to the fourth part of UITableView tutorial where I should you how to create multiple columns in a UITableViewCell


Welcome to the 4th part of the Table View Tutorial. In this tutorial, we will learn how to create a UITableViewCell with multiple columns. In these columns, we can place images and text.

It is recommended that you read the 1st part of the Table View Tutorial here, before reading this one. The source code for this tutorial has been copied from the Part 3 of the Table View Tutorial.

This is how the application will look like when we are done

We are going to add two columns to the UITableViewCell, where one of the column will show the index number and the other column will show some custom text as seen in the image above. To do this we have to customize the UITableViewCell object which is returned in the cellForRowAtIndexPath method.

We can do this in two ways
  1. Inherit from UITableViewCell
  2. Create a simple method which will customize the UITableViewCell.
If this were to be a real world application, I would advice to inherit from UITableViewCell, but to learn how to create multiple columns, we will use a simple method.

Before we dive into the details, we first need to define some macros which will be the offsets, widths and heights of the objects and the UITableViewCell itself. Think of macros for now as a constant which has a proper name which will be substituted with the original value at runtime.

FileName: TableViewController.m - Declared before the implementation begins
#define ROW_HEIGHT 40
#define CELL_WIDTH 320.0
#define LABEL_HEIGHT 20

//Lets define the dimensions of the two columns
//Set the column offset and the width.
#define NUMBER_OFFSET 10.0
#define NUMBER_WIDTH 50.0
#define NUMBER_TAG 1

#define TEXT_OFFSET 60.0
#define TEXT_WIDTH 270.0
#define TEXT_TAG 2

Start by declaring a method called reuseTableViewCellWithIdentifier in TableViewController.h file. This file is created in the Part 1 of this tutorial series. reuseTableViewCellWithIdentifier takes an NSString variable and returns UITableViewCell.

This is how the header file will look like

FileName: TableViewController.h#import <UIKit/UIKit.h>

@class SubViewController;

@interface TableViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {

IBOutlet UITableView *tblView;
SubViewController *svController;

}

@property (nonatomic, retain) UITableView *tblView;
@property (nonatomic, retain) SubViewController *svController;

-(UITableViewCell *)reuseTableViewCellWithIdentifier:(NSString *)identifier;

@end


We then implement the method in TableViewController.m file and this is the source code for the method

FileName: TableViewController.m
-(UITableViewCell *)reuseTableViewCellWithIdentifier:(NSString *)identifier {

//Rectangle which will be used to create labels and table view cell.
CGRect cellRectangle;

//Returns a rectangle with the coordinates and dimensions.
cellRectangle = CGRectMake(0.0, 0.0, CELL_WIDTH, ROW_HEIGHT);

//Initialize a UITableViewCell with the rectangle we created.
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:cellRectangle reuseIdentifier:identifier] autorelease];

//Now we have to create the two labels.
UILabel *label;

//Create a rectangle container for the number text.
cellRectangle = CGRectMake(NUMBER_OFFSET, (ROW_HEIGHT - LABEL_HEIGHT) / 2.0, NUMBER_WIDTH, LABEL_HEIGHT);

//Initialize the label with the rectangle.
label = [[UILabel alloc] initWithFrame:cellRectangle];

//Mark the label with a tag
label.tag = NUMBER_TAG;

//Add the label as a sub view to the cell.
[cell.contentView addSubview:label];
[label release];

//Create a rectangle container for the custom text.
cellRectangle = CGRectMake(TEXT_OFFSET, (ROW_HEIGHT - LABEL_HEIGHT) / 2.0, TEXT_WIDTH, LABEL_HEIGHT);

//Initialize the label with the rectangle.
label = [[UILabel alloc] initWithFrame:cellRectangle];

//Mark the label with a tag
label.tag = TEXT_TAG;

//Add the label as a sub view to the cell.
[cell.contentView addSubview:label];
[label release];

return cell;
}

We achieve the illusion of multiple columns in a UITableViewCell by adding different objects as a sub view to the UITableViewCell. These objects in the UITableViewCell are placed at different offsets and are of different widths.

We start of by declaring an object of type CGRect, which we will use to create frame rectangles and then initialize the UILabel and the UITableViewCell with it. Using a frame rectangle, we can specify the offset, width of the label on the UITableViewCell. We initialize the UITableView object with the help of the cellRectangle which is created using these coordinates and dimensions.

//Rectangle which will be used to create labels and table view cell.
CGRect cellRectangle;

//Returns a rectangle with the coordinates and dimensions.
cellRectangle = CGRectMake(0.0, 0.0, CELL_WIDTH, ROW_HEIGHT);

//Initialize a UITableViewCell with the rectangle we created.
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:cellRectangle reuseIdentifier:identifier] autorelease];


CGRectMake takes four parameters, the first two being the x, y position and the last two being the width, height of the object. Here the UITableViewCell is created the same way as earlier but instead of passing CGRectZero we are passing a rectangle defined by us.

UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:identifier] autorelease];

UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:cellRectangle reuseIdentifier:identifier] autorelease];


We then create a Label and initialize with offset 10,(10 = (40-20)/2). This way the label will be placed 10 pixels away (pixels is probably a wrong word here but I thought it will be easier to understand) and the text will be placed 10 pixels top from the bottom. The other two parameters specify what will be the width and the height of the control. Then we initialize a label using the frame rectangle we just created.

//Now we have to create the two labels.
UILabel *label;

//Create a rectangle container for the number text.
cellRectangle = CGRectMake(NUMBER_OFFSET, (ROW_HEIGHT - LABEL_HEIGHT) / 2.0, NUMBER_WIDTH, LABEL_HEIGHT);

//Initialize the label with the rectangle.
label = [[UILabel alloc] initWithFrame:cellRectangle];


we mark the label using the tag property, so it can be retrieved later using viewWithTag method. The label is then added as a sub view to the contentView property of UITableViewCell object. The memory of the label is released, so it can be reused again.

//Mark the label with a tag
label.tag = NUMBER_TAG;

//Add the label as a sub view to the cell.
[cell.contentView addSubview:label];
[label release];


The same procedure is repeated again, for the second column.

Now we have to set the appropriate text in cellForRowAtIndexPath method and this is how the method will be changed

TableViewController.m
-(UITableViewCell *)tableView:(UITableView *)tblView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *identifier = @"MyCell";

UITableViewCell *cell = [self.tblView dequeueReusableCellWithIdentifier:identifier];
if(cell == nil)
cell = [self reuseTableViewCellWithIdentifier:identifier];

//cell.text = [[NSString alloc] initWithFormat:@"Cell : %i", indexPath.row];

//Now instead of passing data to the text property of the cell.
//We will get the label by tag and set data to the text property of the label

UILabel *lbl = (UILabel *)[cell viewWithTag:NUMBER_TAG];
lbl.text = [NSString stringWithFormat:@"%i. ", indexPath.row + 1];

UILabel *lblText = (UILabel *)[cell viewWithTag:TEXT_TAG];
lblText.text = @"Custom Cell text";

return cell;
}


We call the reuseTableViewCellWithIdentifier to give us a new UITableViewCell object. We then call viewWithTag method on the cell to get the right object added to the contentView of the UITableViewCell. viewWithTag returns id and we cast it to the object we want. In our case we cast it to UILabel.

We get the label for NUMBER_TAG and set current row index number. We add this value by 1, because the row number starts from zero. We get the UILabel by passing TEXT_TAG to viewWithTag method and set some text to the label. Now all we have to do is return the UITableViewCell object as usual.

Click on Build and Go to see the results.

You can download the source code for this project here.

Please let me know your thoughts and if you have any questions you can email me at iphonearticles [@] gmail [.] com. I will reply as I find time, usually over the weekend. You can also post your questions to the iPhone SDK Development group here.



IMPORTANT:
The following tutorial has been deprecated and should no longer be used for any purposes. To learn more on how to use the UITableView click here