1. UITableView-Tutorial – CocoaBits
cocoabits.de /ios/uitableview-tutorial
Dirk Koller
Tabellen sind sehr wichtige Komponenten in der iOS-Entwicklung und finden praktisch in jedem Projekt
Einsatz. Die Möglichkeiten der UITableView sind beeindruckend vielseitig, das Tutorial konzentriert
sich deshalb auf die gängigsten Anwendungsfälle: CRUD sprich Create, Read, Update und Delete mit
Custom Zellen und das Umsortieren von Zellen. Die Screenshots zeigen eine iPhone-App, aber
natürlich funktioniert das Ganze für das iPad ebenso.
Table View Controller Basics
Gestartet wird mit der Projektvorlage Empty Application (File > New > Project… > iOS > Application >
Empty Application). Die leere Anwendung wird durch eine neue Klasse UserTableController (File >
New > File… > iOS > Cocoa Touch > Objective-Class) erbend von UITableViewController ergänzt. Ein
Xib-File dafür wird nicht benötigt. Die Tabelle soll die Liste der Benutzer anzeigen. Damit der neu
angelegte Table View Controller (bzw. dessen Table View) angezeigt wird, ist zunächst eine Instanz der
Klasse als Root View Controller im AppDelegate zu setzen. Wir gehen hier gleich noch einen Schritt
weiter und packen den UserTableController in einen Navigation Controller. Die dadurch erzeugte
Navigation Bar bietet Platz für Buttons (bzw. Bar Button Items) und ist erforderlich für den Wechsel
zum Benutzer Detail View.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]
bounds]];
UserTableController *tableViewController = [[UserTableController alloc]
init];
UINavigationController *navigationController = [[UINavigationController
alloc] initWithRootViewController:tableViewController];
self.window.rootViewController = navigationController;
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Die Datenquelle: Table View Data Source
Im Zusammenhang mit Table Views existieren zwei wichtige Protokolle: UITableViewDataSource und
UITableViewDelegate. Während die Data Source für das Bereitstellen der Daten zuständig ist, geht es
beim Delegate um Aussehen und Aktionen der Tabelle.
Die Superklasse UITableViewController implementiert die beiden erforderlichen Methoden des
Protokolls UITableViewDataSource (numberOfSectionsInTableView: und tableView:
numberOfRowsInSection:). Diese müssen im UserTableController überschrieben werden. Wir
entfernen die Warnings und geben Daten aus einem als Property gehaltenen und in viewDidLoad
gefülltem Array zurück:
2. @property (nonatomic) NSMutableArray *data;
...
_data = [NSMutableArray arrayWithArray:@[@"Maier", @"Müller", @"Schmidt"]];
...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return self.data.count;
}
Durch die Änderungen werden jetzt drei Zellen einer Sektion abgefragt. Die Inhalte der Zelle werden in
tableView:cellForRowAtIndexPath: festgelegt:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier
:@"reuseIdentifier" forIndexPath:indexPath];
cell.textLabel.text = [self.data objectAtIndex:indexPath.row];
return cell;
}
Man beachte im obigen Codeabschnitt dass die Methode
dequeueReusableCellWithIdentifier:forIndexPath: verwendet wird. Tabellenzellen werden aus
Speicher- und Performancegründen in einer Queue gespeichert, wenn sie den sichtbaren Bereich
verlassen. Die genannte Methode erzeugt die Zellen selbständig, wenn noch keine Zellen in der Queue
vorliegen. Sie benötigt dafür allerdings die Information, von welchem Typ die zu erzeugenden Zellen
sein sollen. Diese wird in viewDidLoad durch Aufruf der TableView-Methode
registerClass:forCellReuseIdentifier: gegeben:
[self.tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:@"reuseIdentifier"];
Ein erster Start der App zeigt die drei Zellen mit den Namen der Benutzer.
3. Zellen selektieren: Table View Delegate
Das andere bereits genannte Protokoll im Zusammenhang mit Table Views ist das Table View
Delegate. Es ist zuständig für Aussehen und Verhalten der Tabelle. Alle darin aufgeführten Methoden
sind optional. Die Wichtigste ist tableView:didSelectRowAtIndexPath:, sie wird aufgerufen beim Tap
auf eine Zelle. In der Methode wird zum Beispiel der Wechsel in einen Detail View Controller
ausprogrammiert. Mit Hilfe des übergebenen Index Path lässt sich das passende Datenobjekt ermitteln
und einem Detail Controller (hier UserDetailController) übergeben:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UserDetailController *userDetailController = [[UserDetailController alloc]
init];
userDetailController.lastName = [self.data objectAtIndex:indexPath.row];
[self presentViewController:userDetailController animated:YES completion:^{
//
}];
}
Styles und Custom Zellen
Die Standard-Table View Cell kommt in vier verschiedenen Varianten (UITableViewCellStyle) daher, in
denen maximal zwei Labels und ein Bild verschieden angeordnet angezeigt werden können. Der
Vorteil dieser Styles ist, dass sie vom Aussehen her bekannten Apple Apps entsprechen und keine
eigenen Zellen-Klassen erzeugt werden müssen. Möchte man einen der Stile verwenden, müssen die
Zellen mit der älteren Methode dequeueReusableCellWithIdentifier: (Achtung: ohne forIndexPath:) aus
der Queue geholt werden. Die Zellen werden dabei nicht automatisch erzeugt, dies geschieht danach
mit alloc/initWithStyle:reuseIdentifier:. Bei dieser Variante muss das Registrieren der Zelle entfernt
werden, der Typ wird beim alloc angegeben.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier
:@"reuseIdentifier"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:@"reuseIdentifier"];
}
cell.detailTextLabel.text = [self.data objectAtIndex:indexPath.row];
Genügen die vier vordefinierten CellTypen den Anforderungen nicht, können eigene Zellen erzeugt
werden.
Dazu legt man eine Subklasse von UITableViewCell an (etwa UserCell). Außerdem wird ein leeres Xib
(am besten mit gleichem Namen wie die Subklasse) benötigt. In das Xib wird eine Table View Cell aus
der Komponentenbibliothek gezogen. Die Custom Class der zugefügten Zelle (nicht des Files Owner!)
wird auf den Namen der zuvor angelegten Subklasse UserCell gesetzt. Darüber hinaus wird der Cell
Identifier im Inspektor gesetzt (etwa UserCellIdentifier). Die Zelle kann danach mit den gewünschten
Controls (Labels usw.) gestaltet werden. Damit man die zugefügten Labels auch setzen kann, werden
noch Outlets in der UserCell angelegt (Connections über die Zelle und nicht den File’s Owner!!!).
Eigene Zellen müssen im Code registriert werden - wenn ein Nib-File vorhanden ist, über die Methode
registerNib:forCellReuseIdentifier: des Table View.
4. [self.tableView registerNib:[UINib nibWithNibName:@"MyCell" bundle:nil]
forCellReuseIdentifier:@"Cell"];
Danach kann die Zelle am einfachsten mit der oben bereits beschriebenen neueren Variante der
dequeue-Methode ermittelt werden.
Löschen und der Edit Mode
Der Table View Controller verfügt über einen eingebauten Edit-Modus. Er lässt sich leicht mit Hilfe des
editButtonItem in der Navigation Bar einbinden:
self.navigationItem.rightBarButtonItem = self.editButtonItem;
Ein Tab auf Bearbeiten animiert die Löschen-Button von der linken Seite der Zellen ein und ändert die
Beschriftung des editButtonItems von Bearbeiten auf Erledigt bzw. Done im Englischen.
Das Löschen der Daten erfolgt in der Methode tableView:commitEditingStyle:forRowAtIndexPath:
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete
) {
// Delete the row from the data source
[self.data removeObjectAtIndex:indexPath.row];
// Delete the row from the table view
[tableView deleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert
) {
// Create a new instance of the appropriate class, insert it into the
array, and add a new row to the table view
}
}
5. Verschieben von Zellen
Der Edit-Mode hilft auch beim Verschieben von Zellen. Er blendet die Verschiebe-Handles auf der
rechten Seite der Zelle automatisch ein:
Voraussetzung dafür ist, dass die betroffene Zelle auch wirklich verschoben werden darf. Dies wird in
tableView:canMoveRowAtIndexPath: pro Zelle oder auch pauschal für alle Zellen festgelegt:
- (BOOL)tableView:(UITableView *)tableView
canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
Weiterhin muss in der Methode tableView:moveRowAtIndexPath:toIndexPath: das Verschieben der
Zelle im Datenmodell implementiert werden. Wenn die Zelle im UI verschoben wurde, sollte dies
natürlich auch in dem zugrunde liegenden Array geschehen:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath
*)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
id object = [self.data objectAtIndex:fromIndexPath.row];
[self.data removeObjectAtIndex:fromIndexPath.row];
[self.data insertObject:object atIndex:toIndexPath.row];
[self.tableView reloadData];
}
Zum Weiterlesen
Table View Programming Guide for iOS