Mrz 13 2009

Nav Bar Tutorial (Version 2)

Das zweite überarbeitete Tutorial beschäftigt sich mit der NavigationBar. Dabei handelt es sich um die Navigationsleiste am oberen Bildschirmrand, mit der man beispielsweise von Detailansichten wieder zur Übersicht zurückkommt, oder beim Bearbeiten von Einträgen die beiden Buttons “Save” und “Cancel” anzeigt.

Die UINavigationBar verwendet dabei eine Art Stack auf dem UIViewController Objekte abgelegt werden. Bei der Initialisierung muss in jedem Fall ein root ViewController angegeben werden. Dies ist jene View, die am Anfang angezeigt wird.

Mit den Methoden pushViewController:animated: sowie popViewControllerAnimated: lassen sich zusätzliche UIViewController im UINavigationController einbinden, wobei die Methode pushViewController:animated: den als Parameter angegebenen UIViewController anzeigt. Zusätzlich wird automatisch ein Back-Button auf der linken Seite der NavigationBar erzeugt, welcher den Titel des vorigen ViewControllers anzeigt. Die Methode popViewControllerAnimated: entfernt den aktuellen ViewController wieder und schaltet auf die vorige Sicht zurück.

Eine View, die in einen UINavigationController eingebunden ist, besitzt die Property navigationItem, über welche sich die angezeigte UINavigationBar modifizieren lässt. So enthält die UINavigationItem Klasse die Properties backBarButtonItem, leftBarButtonItem, rightBarButtonItem sowie title. Über diese Properties lassen sich die entsprechenden Buttons bzw. der Titel der in der Navigationbar angezeigt wird modifizieren.

Genug der Theorie. Um das Ganze zu demonstrieren möchte ich eine Applikation erstellen, die drei Views enthält, zwischen denen man mit der NavigationBar umschalten kann. Die erste View soll nur einen Add und Details-Button anzeigen, über die zur zweiten View umgeschaltet werden kann. Auf der zweiten View soll es einen Zurück-Button geben, der wieder auf die erste View zurückschaltet sowie einen Edit-Button der auf die dritte View umschaltet. Die dritte View soll die beiden Buttons Cancel (zurück zur zweiten View) und Save (ebenfalls zurück zur zweiten View) enthalten.

Wie immer beginne ich mit einem neuen Projekt vom Typ iPhone OS Window-Based Application, welche ich NavBar nenne. Dementsprechend erstellt XCode eine Hauptklasse NavBarAppDelegate.m.

Zusätzlich erstelle ich die drei Klassen für die drei Views. Diese sind ebenfalls wieder vom Typ UIViewController subclass, wobei ich diese wieder First, Second und Third taufe.

Die erste View (First.m) soll den Titel First in der NavigationBar anzeigen (Zeile 9) und zusätzlich auf der rechten Seite einen Add-Button (Zeile 10). Zusätzlich wird ein Button in der View angezeigt, der den Titel Details trägt (Zeilen 12-21). Beide Buttons werden mit der Methode buttonPressed verbunden (Zeile 10 und 17). Die Methode buttonPressed initialisiert die nächste View (also Second, Zeile 25) und zeigt diese über den ViewController an (Zeile 27).

First.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#import "First.h"
#import "Second.h"

@implementation First

- (void)loadView {
    [super loadView];

    self.navigationItem.title = @"First";
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(buttonPressed:)];

    UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame = CGRectMake(10.0, 10.0, 300.0, 50.0);
    [button setTitle:@"Details" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
    [tempView addSubview:button];

    [self setView:tempView];
    [tempView release];
}

- (void)buttonPressed:(id)sender {
    Second *second = [[[Second alloc] initWithNibName:nil bundle:nil] autorelease];

    [self.navigationController pushViewController:second animated:YES];
}

@end

Die zweite View enthält durch das laden automatisch einen Back-Button auf der rechten Seite der NavigationBar. Zusätzlich muss ein Edit-Button auf der rechten Seite hinzugefügt werden (Zeile 10) und der Titel auf Second gesetzt werden (Zeile 9). Wenn der Back-Button gedrückt wird, schaltet der NavigationController automatisch auf die vorige View zurück. Bei Benutzung des Edit-Buttons (Zeile 8 ) muss äquivalent zur vorigen View eine neue Instanz der nächsten View erzeugt und auf diese umgeschaltet werden (Zeilen 14-16).

Second.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import "Second.h"
#import "Third.h"

@implementation Second

- (void)loadView {
    [super loadView];

    self.navigationItem.title = @"Second";
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(buttonPressed:)];
}

- (void)buttonPressed:(id)sender {
    Third *third = [[[Third alloc] initWithNibName:nil bundle:nil] autorelease];

    [self.navigationController pushViewController:third animated:YES];
}

@end

Die letzte View besitzt den Titel Third (Zeile 8 ) sowie zwei Buttons in der Navigationbar (Cancel, Zeile 9 sowie Save, Zeile 10). Beide Buttons lösen einen Rücksprung zur vorigen View aus (Zeile 14):

Third.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import "Third.h"

@implementation Third

- (void)loadView {
    [super loadView];

    self.navigationItem.title = @"Third";
    self.navigationItem.leftBarButtonItem  = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(buttonPressed:)];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave   target:self action:@selector(buttonPressed:)];
}

- (void)buttonPressed:(id)sender {
    [self.navigationController popViewControllerAnimated:YES];
}

@end

Im Hauptprogramm (NavBarAppDelegate) muss nun eine Instanz der ersten View (der Root View) erstellt werden (Zeile 11) und ein UINavigationController mit dieser initialisiert werden (Zeile 12). Anschließend wird der Navigation Controller als View der Applikation aktiviert (Zeile 14).

NavBarAppDelegate.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#import "NavBarAppDelegate.h"
#import "First.h"

@implementation NavBarAppDelegate

@synthesize window;

UINavigationController *navController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    First *firstView = [[First alloc] initWithNibName:nil bundle:nil];
    navController = [[UINavigationController alloc] initWithRootViewController:firstView];

    [window addSubview:[navController view]];

    [window makeKeyAndVisible];
}

- (void)dealloc {
    [window release];
    [navController release];

    [super dealloc];
}

@end

Auch hier erspare ich es mir das ganze Projekt als Source hochzuladen, da auch dieses noch recht trivial ist. Die nächsten geplanten Tutorials sind: Kombination UITabBar mit UINavigationBar, UITableView sowie Delegation. Sowie eventuell etwas über Cocoa-Memorymanagement. Mal schauen…


Mrz 11 2009

Tab Bar Tutorial (Version 2)

Nachdem ich ja bereits geschrieben habe, dass ich inzwischen vom Interface Builder abgekommen bin (zumindest Großteils; um eine View zu entwerfen und die Daten dann im Code zu übernehmen ist der IB durchaus ganz brauchbar) beginne ich mal mit der ersten Anleitung ohne den IB.

Wie bereits zuvor beginne ich mit einer TabBar Applikation. Dabei soll einfach eine Applikation entstehen, die 2 verschiedene Views enthält, zwischen denen man mit Hilfe einer TabBar umschalten kann. Das grundsätzliche Vorgehen bei der Projekterstellung bleibt dabei gleich, d.h. zuerst wird ein neues Projekt vom Typ iPhone OS Window-Based Application erstellt. Da ich die Applikation TabBar genannt habe, erzeugt XCode eine Hauptklasse TabBarAppDelegate.m.

Zusätzlich dazu erstelle ich zwei weitere Klassen, für jede View eine eigene Klasse, die vom Typ UIViewController subclass sind, und die ich sinnvollerweise First.m sowie Second.m nenne. In jeder dieser beiden Views erstelle ich in der Methode loadView ein Label, welches den Text “First View” bzw. “Second View” anzeigen soll. Diese beiden Klassen sind eigentlich selbsterklärend und sehen wie folgt aus (die Header-Dateien First.h und Second.h habe ich dabei nicht modifiziert):

First.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import "First.h"

@implementation First

- (void)loadView {
    [super loadView];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
    label.textAlignment = UITextAlignmentCenter;
    label.text = @"First View";

    [self setView:label];

    [label release];
}

@end

Second.m:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import "Second.h"

@implementation Second

- (void)loadView {
    [super loadView];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
    label.textAlignment = UITextAlignmentCenter;
    label.text = @"Second View";

    [self setView:label];

    [label release];
}

@end

Im Hauptprogramm, d.h. in der TabBarAppDelegate erstelle ich von jedem der beiden ViewController First und Second eine neue Instanz (Zeile 13 und 14). Ein ViewController besitzt die Property tabBarItem, bei der man den Titel angeben kann (.title), der auf dem zugehörigen Tab dargestellt werden soll, sowie auch ein dazugehöriges Icon (.image). Die beiden Tabs werden hier ebenfalls mit “First” und “Second” tituliert (Zeile 16 und 17). Anschließend wird ein neuer UITabBarController erstellt (Zeile 19) sowie mitgeteilt welche Views (bzw. Tabs) er darstellen soll (Zeile 20). Letztendlich wird dem aktuellen Window der Applikation der UITabBarController als Subview gesetzt (Zeile 22).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#import "TabBarAppDelegate.h"

#import "First.h"
#import "Second.h"

@implementation TabBarAppDelegate

@synthesize window;

UITabBarController *tabBarController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {  
    First  *firstViewController  = [[First  alloc] initWithNibName:nil bundle:nil];
    Second *secondViewController = [[Second alloc] initWithNibName:nil bundle:nil];

    firstViewController.tabBarItem.title  = @"First";
    secondViewController.tabBarItem.title = @"Second";
   
    tabBarController = [[UITabBarController alloc] init];
    tabBarController.viewControllers = [NSArray arrayWithObjects:firstViewController, secondViewController, nil];

    [window addSubview:[tabBarController view]];

    [firstViewController  release];
    [secondViewController release];

    [window makeKeyAndVisible];
}

- (void)dealloc {
    [tabBarController release];

    [window release];
    [super dealloc];
}

@end

Und das war schon die ganze Hexerei. Irgendwie weitaus einfacher und schneller als mit dem Interface Builder, und außerdem weiß man so in etwa was dabei passiert. Da das ganze so trivial ist halte ich es nicht für notwendig ein Archiv des Projektes zum Download zur Verfügung zu stellen, ich kann es bei Bedarf aber durchaus gerne weitergeben.