15.05.2012
Xcode 4, iPhone, Cocoa Touch, iOS4, iOS5
Tutorial: UITableView mit NavigationController
In diesem Tutorial wird erklärt, wie eine UITableView
erstellt wird, die beim Klick auf eine Tabellenzeile eine neue View öffnet. Von der View kann über einen UINavigationController
wieder zurück in die UITableView
navigiert werden.
Dieses Tutorial setzt auf dem Beispiel aus Tutorial UITableViewController mit Sections auf.
Die folgenden beiden Screenshots zeigen die fertige iPhone-App:
Als erstes wird eine Detailansicht mit ⌘+N angelegt. In dem Fenster wählt man unter iOS den Eintrag Cocoa Touch aus. Als Template wird Objective-C class selektiert und mit Next bestätigt.
Als Namen für die Class wählt man DetailViewController und klickt auf Next.
Dann wird mit Create die Klasse erzeugt.
Nun muß in der Interface-Datei DetailViewController.h noch festgelegt werden, daß es sich um einen ViewController handelt. Dazu wird einfach UIViewController
ergänzt, so daß der Inhalt folgendermaßen aussieht:
// // DetailViewController.h // TableViewApp // // Created by Jörn Hameister on 15.05.12. // Copyright (c) 2012 http://www.hameister.org. All rights reserved. // #import <Foundation/Foundation.h> @interface DetailViewController : UIViewController @end
Dieser Schritt ist wichtig, da sonst im nächsten Schritt keine Verbindung zwischen File's Owner und DetailViewController
hergestellt werden kann.
Als nächstes wird eine neue XIB-Datei für den DetailViewController
mit ⌘+N angelegt. In dem Fenster wählt man unter iOS den Eintrag User Interface aus. Als Template wird Empty selektiert und mit Next bestätigt.
Als Device Family läßt man unverändert iPhone stehen und bestätigt den Dialog mit Next.
Unter Save As: wird den Name der XIB-Datei eingetragen. Da ViewController und zugehörige XIB-Datei den gleichen Namen haben sollten, wählt man DetailViewController und schließt den Dialog mit Create
Nun öffnet sich der Interface Builder mit einer leeren Ansicht. Dort sucht man in der Object Library nach UIView und zieht diese nach links in Oberfläche.
Nun wird File's Owner selektiert und im Identity inspector als Class der Name des ViewControllers DetailViewController eingetragen. Abschließend wird mit einem ctrl-Klick auf den File's Owner die Verbindung zwischen dem Outlet view und der grünen View hergestellt.
Als erstes wechseln wir in den Editor Assistent mit ⌥⌘↩ und sorgen dafür, daß links DetailViewController.xib
und rechts DetailViewController.h
angezeigt wird.
In der Object Library sucht man nun nach UILabel und zieht das Label nach links in UIView
und paßt die Größe an. Anschließend kann die Ausrichtung (Alignment) des Labels angepaßt werden, so daß der Text mittig angezeigt wird.
Da das Label vom DetailViewController
aus gefüllt werden soll, muß ein Outlet dafür erstellt werden. Dazu selektiert man das Label und zieht mit ctrl und gedrückter Mousetaste eine Linie in die Header-Datei auf der rechten Seite.
In dem Dialog trägt man als Name den Wert labelFontType ein.
Was jetzt im DetailViewController
noch fehlt, ist eine Property zum Setzen des Font-Namen. Deshalb wird in der Header-Datei die folgende Zeile ergänzt.
@property (nonatomic, strong) NSString* fontName;
Außerdem muß in der Datei DetailViewController.m
der Aufruf @synthesize fontName;
hinzugefügt werden. Nun kann vom ViewController
aus der fontName
gesetzt werden.
Als letztes muß noch die Methode viewWillAppear:
ergänzt werden. Diese Methode wird aufgerufen, wenn die View angezeigt wird. Das ist eine gute Stelle um in dem Label den Font-Namen zu setzen, der angezeigt werden soll.
-(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; labelFontType.font = [UIFont fontWithName:self.fontName size:30.0]; labelFontType.text = self.fontName; }
Für das Label wird hier der Font-Type anhand des übergebenen Namens gesetzt. Außerdem wird als text
der Font-Name in das Label geschrieben.
Jetzt ist der DetailViewController
fertig. Damit er benutzt werden kann, müssen folgende Dinge ergänzt werden:
- Für die
UITableViewCells
muß ein AccessoryType zum Navigieren in die DetailView hinzugefügt werden. - Damit auf den Klick in die Tabellenzelle reagiert wird, muß der
ViewController
eine Methode desUITableViewDelegate
implementieren. - Der
UINavigationController
muß als RootViewController gesetzt werden.
Der AccessorType wird in der Methode tableView:cellForRowAtIndexPath:
gesetzt indem das Property accessoryType
von cell
mit einem der folgenden Werte belegt wird:
- UITableViewCellAccessoryNone
- UITableViewCellAccessoryDisclosureIndicator
- UITableViewCellAccessoryDetailDisclosureButton
- UITableViewCellAccessoryCheckmark
Standardmäßig ist der erste Werte gesetzt. Wir verwenden in dem Beispiel den zweiten Wert, wie in folgender Methode zu sehen ist.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"]; if(!cell) { cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"]; //Details button cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; } [[cell textLabel] setText:[self.model fontNameAtIndex:[indexPath row] inFamily:[indexPath section]]]; return cell; }
Anschließen wird in der Datei ViewController.m
folgende Methode ergänzt:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { DetailViewController* detailsViewController = [[DetailViewController alloc]init]; [detailsViewController setFontName:[self.model fontNameAtIndex:[indexPath row] inFamily:[indexPath section]]]; [[self navigationController] pushViewController:detailsViewController animated:YES]; }
In ihr wird der DetailViewController
initialisiert und der fontName
wird gesetzt. Außerdem wird der detailViewController
dem navigationController
übergeben.
Da die Methode Teil des UITableViewDelegate
ist, würde man normalerweise erwarten, daß man die Header-Datei um diesen Delegate erweitern muß, damit die Methode aufgerufen wird. Dies ist aber nicht der Fall. Grund dafür ist, daß der ViewController
keine Nib/Xib-Datei besetzt. In diesem Fall wird der Delegate einfach auf self
gesetzt.
Was jetzt noch fehlt, ist das Setzen des UINavigationController
als RootController. Das muß in der Datei AppDelegate.m
gemacht werden. Also wird die Methode application:didFinishLaunchingWithOptions:
so angepaßt, daß sie folgendermaßen aussieht:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. ViewController* vc = [[ViewController alloc]init]; UINavigationController* nc = [[UINavigationController alloc]initWithRootViewController:vc]; [[self window]setRootViewController:nc]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
Prinzipiell ist die App nun lauffähig, allerdings stört auf der ersten Seite noch die leere Navigation-Bar oben. Bei dieser App wird sie nicht benötigt und soll ausgeblendet werden. Außerdem steht in der Navigation-Bar auf der zweiten Seite in den Zurück-Button Back. Es wäre schöner, wenn dort Zurück stehen würde.
Also wird beim Erscheinen der UITableView
einfach die UINavigationBar
ausgeblendet. Dazu ergänzt man folgende Methode in der Datei ViewController.m
:
-(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.navigationController setNavigationBarHidden:YES]; }
Nun muß man dafür sorgen, daß sie in der DetailView wieder eingeblendet wird. Dazu ergänzt man in der Datei DetailViewController.m
die dritte Zeile:
-(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.navigationController setNavigationBarHidden:NO]; labelFontType.font = [UIFont fontWithName:self.fontName size:30.0]; labelFontType.text = self.fontName; }
Zum Ändern des Titels des Back-Button muß die init
-Methode in der Datei ViewController.m
angepaßt werden.
- (id)init { self = [super initWithStyle:UITableViewStyleGrouped]; if (self) { UINavigationItem *n = [self navigationItem]; n.title = @"Zurück"; } return self; }
Es wird einfach das UINavigationItem
vom NavigationController abgefragt und der title
angepaßt.
Nach dem Kompilieren und Starten mit ⌘+R öffnet sich der Simulator und zeigt die App an.
Als kleine Fingerübung kann man den DetailViewController
um einen UISlider
, ein UILabel
und ein UITextView
erweitern, so daß die Detailansicht folgendermaßen aussieht:
Apps, die diese Funktionalität haben, findet man im AppStore. Unglaublich, aber wahr!