A table in Cocoa Touch represents a vertical list of items, with
each item assigned to a cell or row in the table. If the list of items is multi-dimensional, such as a list of
email messages in the Mail application, each table cell should display a
succinct summary, label, or other high-level indication of the object
assigned to the cell. Users can get additional information for each row by
tapping the row. When a user taps the row, an event is sent to the
delegate of the table, which is an object that conforms to the
UITableViewDelegate protocol. This protocol defines
methods for handling interaction with cells. A table delegate defines the
methods it wishes to handle, and the table controller automatically
handles the communication between the user interface and the delegate.
(The availability of free implementations of design patterns like the
delegate pattern is one of the benefits that Cocoa Touch controller
classes offer developers.)You can embed UIControl instances in table cells
to add functionality within the context of a single row in your dataset.
For example, users will often need to delete a record using a button, as
with the Mail application, or change the order of rows in a table. The
table delegate protocol, UITableViewDelegate, allows
developers to handle user-initiated edits like reordering, deletion,
and insertion of new rows into the table.
The controls you use in table cells should be chosen with attention
to the interactive nature of the tables and cells themselves. Most tables
are embedded in a scrolling view that responds to gestures with movement
along the y-axis. In those cases, it would be difficult to present users
with an embedded control that also responds to gestures along the y-axis.
Tables that act as views for navigation controllers and allow users to
drill down through a hierarchical dataset already handle taps.
Adding controls to table cells is simple. There are three approaches
to developing custom table
cells:
Create an instance of UITableViewCell and set its public
properties, using the default object and layout with custom
content.
Create an instance of UITableViewCell and
customize it using public properties and methods for managing
subviews. This can include adding subviews to the
contentView of the cell, setting the
accessoryView appropriately, adding an icon or
image to the left side of the cell using the imageView property, and manipulating
the visual characteristics such as background color and text
properties. In most cases, a standard
UITableViewCell is an appropriate starting point
because it provides customized
consistency in the user experience.
Subclass UITableViewCell with overrides for
initialization, layout, and event handling, and add any functionality
desired.
The simplest option is to create an instance of
UITableViewCell and customize it using properties.
Working with standard cell properties minimizes the amount of code
required for customization, which in turn limits the risk of bugs. Users
benefit from standard cells because familiarity speeds the learning curve
for new users.
Adding subviews to a standard UITableViewCell is
slightly more complex. Developers must manage the layout of subviews and
support resizing and repositioning subviews to support rotation. In
exchange, more customization is possible.
The most complex and flexible option is to subclass
UITableViewCell. Developers can override the core
functionality of a cell to render complex artwork or manage touch events
in novel ways.
Standard table view cells include three subviews that display
content to users. On the left side of each cell is a view called
imageView. The center and majority of the cell is
occupied by a view that displays the main cell content, sensibly called
the contentView. To the right of the
contentView is a subview that can display standard
indicators such as a checkmark, chevron, custom graphic, and even
controls. The view for accessories is called the accessoryView.
1. Passive Indicators
The disclosure indicator is a familiar control for diving deeper
into a stack of UINavigationController instances from
within a UITableView. The disclosure indicator looks like a chevron and shows
that more information is available for a row. You can set the indicator
type for a cell by setting the accessoryType property
of the UITableCell
instance to UITableViewCellAccessoryDisclosureIndicator:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"OMG_Its_a_Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.text = [nodes objectAtIndex:indexPath.row];
return cell;
}
You can display a checkmark as an accessory by assigning the
UITableViewCellAccessoryCheckmark
constant to accessoryType:
cell.accessoryType = UITableViewCellAccessoryCheckmark;
Assigning a custom image to an accessory view is nearly as
simple:
cell.accessoryView = [[[UIImageView alloc] initWithImage:myImage] autorelease];
2. Active Indicators and Control Accessories
Developers can assign any UIView to the
accessoryView property, including
controls like sliders, buttons, and switches.
If the additional detail for the object represented by the cell
consists of configuration options, or if the cell has multiple subviews
that track touches independently, you can use a detail disclosure button by assigning UITableViewCellAccessoryDetailDisclosureButton
to the accessoryType property of the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"OMG_Its_a_Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
cell.text = [nodes objectAtIndex:indexPath.row];
return cell;
}
Disclosure buttons handle user interaction separately from the
cells in which they are embedded. To respond to user interaction for a
disclosure button in an accessoryView, define a
tableView:accessoryButtonTappedForRowWithIndexPath:
method in your table view’s delegate:
- (void)tableView:(UITableView *)tableView
accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
// Forward the message to the tableView:didSelectRowAtIndexPath:
// method. You can do anything you want here. You may want to
// treat disclosure buttons separately from the cell, showing
// a configuration screen instead of a detail screen, for example.
[self tableView:tableView didSelectRowAtIndexPath:indexPath];
}
Disclosure buttons can also be used outside of tables. The simple
clarity and ubiquity of disclosure buttons across applications enable
users to understand that more information is available for the selected
context:
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
// Add a disclosure detail button to the view.
disclosure = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[self addSubview:disclosure];
disclosure.center = CGPointMake(270.0, 20.0);
[disclosure addTarget:self action:@selector(disclose:)
forControlEvents:UIControlEventTouchUpInside];
// Other setup here.
}
return self;
}
You can use custom buttons or other controls as accessories by
adding them to the accessoryView. If you create a
custom control for your accessoryView, you will need
to use the target-action mechanism to capture the events generated by
user interaction.