Custom Table View Cells In iPad Programming

The UITableViewCell class can be configured to display in a variety of standard ways, but sometimes we want to display content in a cell that cannot be fit into one of the standard display modes. In this blog, we’ll use a table view to display a series of customized cells. So, let’s get started!

Start Xcode, select “Create a new Xcode project,” choose the Empty Application template, and click Next. Name the project CustomCells, and select options as shown:

Click Next, choose a location to save the project, then click Create.

We’ll be adding two new files to the project, a UITableViewController, and a xib file for our custom cell.

Choose File | New > File… from the menu, and add a UITableViewController named TableViewController as shown:

We do not need a xib file for this controller. Click Next and save the file in the default location by clicking Create.

Again choose File | New > File… from the menu, and this time create an empty xib file by selecting Empty in the User Interface section:

Click Next, make sure the Device Family is set to iPad, click Next, and save the file as CellNib in the default location by clicking Create.

Open the CellNib.xib file you just created. Drag a UITableViewCell from the library to the empty surface of the xib file, then add labels to the cell as shown here:

Set the text and for the labels as shown. In this example, the font size of the first label is 27, and it is set to System Italic. All other labels have the default font and size.

The next step is to set a tag value for each label that still has the text “Label.” Set the tag value for the large italic label to 1, then set tag values of 2, 3, 4, and 5 for the remaining “Label” labels to the right of Address 1:, Address 2:, Phone:, and Cell:.

In order for the table view controller to find this xib and use it as a template for each of its cells, we’ll need to change File’s Owner’s class in the xib. Select File’s Owner, then in the identity inspector, change the Class to “TableViewController” as shown here:

In the properties of the actual cell, set the identifier to Cell. We’ll be returning to this xib file in just a moment to wire up the cell to a property in the TableViewController, but first we have to create that property.

Open TableViewController.h and make these changes to the file:

1

2

3

4

5

6

7

8

#import <uikit/UIKit.h>

@interfaceTableViewController:UITableViewController

@property(nonatomic,strong)NSArray *cellContent;

@property(nonatomic,strong)IBOutlet UITableViewCell *customCell;

@end

In this demo, we define an array to hold the content of the cells. We also define a UITableViewCell as an outlet called customCell. Save the file, then return to CustomCell.xib. Wire the customCell outlet to the cell as shown:

Now open TableViewController.m and make these changes:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

#import "TableViewController.h"

@interfaceTableViewController()

@end

@implementation TableViewController

@synthesize cellContent,customCell;

-(NSArray *)cellContent

{

cellContent=[[NSArray alloc]initWithObjects:

[NSArray arrayWithObjects:@"Alex Ander",

@"213 4th St.",@"Apt. 17",@"555-555-5555",@"111-111-1111",nil],

[NSArray arrayWithObjects:@"Jane Doe",

@"4 Any Ave.",@"Suite 2",@"123-456-7890",@"098-765-4321",nil],

[NSArray arrayWithObjects:@"Bill Smith",

@"63 Smith Dr.",@"",@"678-765-1236",@"987-234-4987",nil],

[NSArray arrayWithObjects:@"Mike Taylor",

@"3145 Happy Ct.",@"",@"654-321-9871",@"654-385-1594",nil],

[NSArray arrayWithObjects:@"Nancy Young",

@"98 W. 98th St.",@"Apt. 3",@"951-753-9871",@"951-654-3557",nil],

nil];

returncellContent;

}

-(id)initWithStyle:(UITableViewStyle)style

{

self=[superinitWithStyle:style];

if(self){

// Custom initialization

}

returnself;

}

-(void)viewDidLoad

{

[superviewDidLoad];

// Uncomment the following line to preserve selection between presentations.

// self.clearsSelectionOnViewWillAppear = NO;

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.

After synthesizing the properties, we override the getter of cellContent to lazily instantiate it to an array of arrays of strings holding names, addresses, and phone numbers. Since there is only one section in this table view, the numberOfSectionsInTableView: method returns 1. The numberOfRowsInSection: method just returns the count of inner arrays in the cellContent array.

In heightForRowAtIndexPath: we must return the height of the cell in CustomCell.xib. If you are entering this code from scratch, your cell height will most likely be a different value.

In order to change the background color of a cell, we must define the delegate method tableView: willDisplayCell: forRowAtIndexPath: method. This is the only opportunity we have to alter the background color of a UITableViewCell’s underlying view.

The tableView: cellForRowAtIndexPath: method first attempts to get a reusable cell. If there is no cell (cell == nil), then we load the nib file from the bundle (which populates the customCell property), set the cell to the customCell, then set the value of customCell to nil (so it doesn’t remain on the heap). After this, we configure the labels on the cell using their tags. Each label’s text is set to a value in the cellContent array. At the end of the method, we return the cell.

TableView: didSelectRowAtIndexPath: is shown here, but not implemented. We would most likely push a new view controller in response to the selection.

Only one thing remains: we must set up the views in AppDelegate in order for them to be displayed in the window. Open AppDelegate.h and make these changes:

1

2

3

4

5

6

7

8

9

10

#import <uikit/UIKit.h>

#import "TableViewController.h"

@interfaceAppDelegate:UIResponder

@property(strong,nonatomic)UIWindow *window;

@property(strong,nonatomic)TableViewController *tableViewController;

@property(strong,nonatomic)UINavigationController *navController;

@end

Make the following changes to the application: didFinishLaunchingWithOptions: method in AppDelegate.m. Remember to synthesize tableViewController and navController in AppDelegate.m as well!

Now run the application, and note that the default cells in the tableViewController have been replaced by our custom cells:

Table View Cells created in this way can contain any control; they are not limited to containing labels and images only. Since File’s Owner is the TableViewController, any action methods must be declared and defined in the view controller class, and will need to detect which cell contains the control being interacted with. But that is the subject of another blog…

I’m struggling to get custom cells working for me and this has helped with a few insights. However, I’m getting a strange error in that my TableViewController class’s cellForRowAtIndexPath method is not getting called and I don’t know why this could be. The initWithStyle and viewDidLoad methods are being called. I can’t figure out what’s going wrong there.

Also, I think this line (in numberOfRowsInSection) may be a mistake:
return [[self.cellContent objectAtIndex:0] count];

You’re returning the number of values in a person’s record, instead of the number of records. In the example, the value returned is 5 either way so it doesn’t matter. If you added more people, the value returned by this would still be 5.