The iPhone documentation discusses a technique for laying out certain types of tables in NIB files; you add the table’s cells to the NIB file, connect them to outlets that you add to the table view controller, and then write a simple tableView:cellForRowAtIndexPath:
function that returns the proper cell for the proper index path. There’s a little pitfall to this approach if your cells have non-standard heights, having to do with the fact that the frames
of UITableViewCells
are changed by the framework after you return them from the UITableViewDataSource
.
Non-Standard Heights
If you want to create table cells with heights other than the default you must implement the tableView:heightForRowAtIndexPath:
UITableViewDelegate
method. If you’re using the layout method outlined above, you might be tempted to include something like this in your implementation:
return nameCell.frame.size.height;
(This assumes that nameCell
is the member of the delegate/controller that points to the UITableViewCell
that should be displayed at the index path that triggers this code snippet.)
This will not work. The problem has its origins in the fact that the framework modifies the frames of the UITableViewCells
returned from the data source; specifically, it seems to regularly increase their heights by one pixel. The effect of this behavior, if combined with the sort of code seen in the above snippet, is that the first time a cell at a particular index path is drawn, it will be assigned the proper height. The next time, however, it will be assigned a height 1 pixel too large. The next, 2 pixels too large. The nth time it is drawn, n-1 pixels too large.
Workaround
To avoid this problem, you need to cache the cell’s original height. I find that code like this works well:
return nameHeight?nameHeight:(nameHeight=nameCell.frame.size.height);
(This assumes that nameHeight
is a CGFloat
member of the delegate/controller.)
Example
Here’s a slightly longer example; these functions comprise the core cell generation and height lookup functions for a 2-section table which has one cell in each section, and was laid out using the NIB method described at the beginning of this post:
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
switch (indexPath.section)
{
case 0:
return nameCell;
case 1:
return descCell;
default:
return nil;
}
}
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
switch (indexPath.section)
{
case 0:
return nameHeight?nameHeight:(nameHeight=nameCell.frame.size.height);
case 1:
return descHeight?descHeight:(descHeight=descCell.frame.size.height);
default:
return 44;
}
}