We talk several times in iPhone in Action about the importance of tables as a central programming paradigm on the iPhone. The problem with this methodology is that, by default, a listing of black text on white backgrounds just doesn't look that interesting. As an example, I offer the table shown at right, a part of an app that I've been working on which very simply lists a game character's name and level, while offering a chevron to click through to a page with more information.
This table is simple and utilitarian. It provides the information that's required, but with very little attention to beauty ... and as such it falls down a little when viewed alongside some of the standard iPhone apps, because Apple did spend a bit of time figuring out how to make their tables look nicer, as you can see if you call up some of the Apple programs, such as iPod, Mail, and Photos.
Generally, Apple uses two tricks to make their tables look nicer:
First, they often have a picture off to the left of each table cell, that in some way depicts the individual item described in the cell. In iPod, that's usually an album picture, in Mail that's a simple icon to describe each of your mail boxes, and in Photos that's a thumbnail of the most recent photo in the set.
Second, Apple often provides a variety of information within a table cell. The iPod list of albums shows off a really standard mechanism. It displays two rows of text: the first one in bold, listing the album name, and the second in normal, GrayColor text, showing the artist name. Mail's folder page shows another example: sender name, subject, time, and content are shown in a variety of sizes, weights, and colors.
Returning to contentView
So, how do you make your table views attractively depict a variety of content and/or pictures? The answer is to make use of the table feature that I described in the first article in this series: contentView.
At the time I described contentView mainly as a tool that you could use to mimic a specific sort of Setting. However, you've probably already realized that its utility can go far beyond that. You can also use it to hold together all the building blocks that make up a more complex cell, whether they be images or text.
At right, I've shown how I rebuilt my page out of three building blocks. First up is a button (masquerading as an image) which I place to the left. Second is a large, bold UILabel listing the name of the character. Third is the level, sitting below the character in darkGrayColor text of a smaller size.
Building these cells was a simple process of creating the three object types that I wanted, positioning each within the bounds of the cell, then adding each to the content view in turn.
Following is a somewhat shortened look at how these things were all done:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier] autorelease];
} else {
NSArray *cellSubs = cell.contentView.subviews;
for (int i = 0 ; i < [cellSubs count] ; i++) {
[[cellSubs objectAtIndex:i] removeFromSuperview];
}
}
UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(65,0,205,35)];
...
[cell.contentView addSubview:nameLabel];
[nameLabel release];
UILabel *levelLabel = [[UILabel alloc] initWithFrame:CGRectMake(65,30,205,20)];
...
[cell.contentView addSubview:levelLabel];
[levelLabel release];
NumberedButton *checkbutton = [NumberedButton
buttonWithType:UIButtonTypeCustom];
...
[cell.contentView addSubview:checkbutton];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
There are two gotchas to contentViews that I didn't cover in my prior article on the topic.
First, when you're adding subviews to your contentView, you have to be careful about not creating a memory leak by recreating the same subviews again and again.
Often you'll only create a subview when you create a cell for the first time (cell == nil). In this case I instead removed the old subviews on subsequent returns to this function (because the cells can be easily moved around, meaning that the new cell content may no longer match the old subview; it'd still probably be better to use the old subviews, and I suspect I'll update that before I send the project off to the app store).
(And indeed I did; you can find my updated code in: Part 3B.)
Second, you need to either build within the constraints of a table cell's standard height (about 30 pixels) or else explicitly change the height. If you're displaying multiple rows of text, as in my example, you'll probably do the latter. The following appears in my table's ViewDidLoad:
self.tableView.rowHeight = 55;
The result of an extra 20 or 30 lines of code and $5 worth of (great) stock art is a table that's vastly more interesting.
Adding Color to the Mix
Apple usually stops right here in their table beautification. However, two of their standard apps show off a bit more ... color.
The Weather app looks quite attractive because of great use of graphics and because it colors tables in alternating shades of gray (though the Weather app might actually mimic a table rather than using one explicitly).
The Notes main page shows a great use of a yellow background and a brown navigation bar which together imply a pad of legal paper.
You can similarly color your tables with two simple variables.
To color your Navigation Controller's Navigation Bar, set its tintColor property.
To color your page backgrounds, set the backgroundColor of your table view controller's view.
When you're working with table cell subviews, you'll need to set the background color of those as well. The easiest solution is probably to set them to the color of their table view or else to a clearColor, so that you only have to adjust the color of your application in one place.
Following is a code snippet from my app delegate, which depicts how I quickly colored all of the navigation bars and all of the views in my application.
for (int i = 0 ; i < 3 ; i++) {
[[[tabBar.viewControllers objectAtIndex:i] navigationBar]
setTintColor:[UIColor colorWithRed:.4 green:.2 blue:.6 alpha:1]];
[[[[tabBar.viewControllers objectAtIndex:i] topViewController] view]
setBackgroundColor:[UIColor colorWithRed:.8 green:.8 blue:1 alpha:1]];
}
The results are shown above. I invite you to compare them to the table at the top of this article, and decide which one you'd prefer to have in your app.
Some icons by Joseph Wain / glyphish.com
Weapons stock art by Rita (SaDE) / DriveThruRPG.com