zurück zum Artikel

Entwickeln für das iPad

Oliver Szymanski

Nach dem iPhone erobert nun auch das iPad einen lange Zeit für nebensächlich erachteten Markt. Da das Design der grafischen Oberfläche, die Ergonomie und die Performance wichtiger denn je sind, ist ein Umdenken angesagt, wenn man für Apples neues Stück Hardware Anwendungen schreiben will.

Nach dem iPhone erobert nun auch das iPad einen lange Zeit für nebensächlich erachteten Markt. Da das Design der grafischen Oberfläche, die Ergonomie und die Performance wichtiger denn je sind, ist ein Umdenken angesagt, wenn man für Apples neues Stück Hardware Anwendungen schreiben will.

Apple bezeichnet das iPad [1] als "magisches und revolutionäres Gerät [2]". Doch die Idee eines Tablet-PCs ist nicht neu, und auch auf Hardwareseite überrascht das iPad nicht. Solche Geräte gibt es schon seit Jahren. Aber sie haben es nicht geschafft, relevante Marktanteile zu erobern. Das wird sich wohl ändern, denn Apple hat in den ersten 28 Tagen seit Markteinführung immerhin eine Million Geräte verkauft. Das ist weit mehr als zum gleichen Zeitpunkt bei der Einführung des iPhones, dessen Erfolg heute niemand mehr anzweifelt.

Für die Entwicklung von iPad-Applikationen nutzt man das gleiche SDK, das auch für die iPhone-Entwicklung notwendig ist. Somit stehen einige der neuen Funktionen, die mit der Einführung des iPads ins Framework gekommen sind, auch für Apples kleinere mobile Geräte zur Verfügung. Als Programmiersprache ist Objective-C vorgegeben. Diese nachrichtenorientierte Sprache basiert auf C/C++ und verlangt vom Entwickler somit allein durch Header-Dateien und Speicherverwaltung mehr Arbeit als bei der Programmierung von Android-Anwendungen. Weiteres Teil des SDK ist der iPad-Simulator zur Ausführung der erstellten Apps.

Bei einem Touch-Gerät wie dem iPad steht die grafische Oberfläche der Apps im Fokus. Daher hat sich im neuen SDK viel bei den Views getan, aus denen die grafischen Oberflächen bestehen.

Die App-Oberflächen sind streng nach dem Modell-View-Controller-Prinzip (MVC) zu programmieren. Entwickler können die Views entweder programmatisch auf Codeebene zusammenbauen oder mit einem Designer erstellen. Ein View erhält zur Laufzeit einen Controller, und die anzuzeigenden Daten entsprechen dem Modell. Die folgenden View-Arten halfen bereits bei der Darstellung von Informationen auf dem Display der kleineren Geräte:

Das neue Framework sieht folgende neuen Views vor:

Gerade eine Kombination aus SplitView und Popover ergibt Sinn, wenn man das Display des iPad optimal ausnutzen möchte. Wird das iPad quer (Landscape-Modus) gehalten, zeigt man zwei Views am besten nebeneinander an. Bei hochkanter Position (Portrait-Modus) nutzt man den Popover, um bei Bedarf einen der Views anzuzeigen.

Damit die Position des iPads Einfluss auf ein Programm hat, müssen alle beteiligten ViewController die shouldAutorotateToInterfaceOrientation-Methode überschreiben, was die gewünschte Orientierung erlaubt. Gerade beim iPad sollten Anwendungen immer darauf vorbereitet sein, dass der Nutzer das Gerät beliebig halten kann. Das fängt damit an, dass man das Startfenster bei iPad-Anwendungen für alle Orientierungen optimiert hinterlegen sollte. Sind die einzelnen Views und ihre ViewController vorhanden, wird der SplitView angelegt.

// Erzeugen des ersten ViewController
TreeViewController *treeView = [[TreeViewController alloc]
initWithNibName:@"Tree"
bundle:[NSBundle mainBundle]];
// Erzeugen des zweiten ViewController
ContentViewController *contentView = [[ContentViewController alloc]
initWithNibName:@"Content"
bundle:[NSBundle mainBundle]];
// Erzeugen des Split ViewController
UISplitViewController *splitController =
[[UISplitViewController alloc] init];
// Die ViewController bekannt machen
splitController.viewControllers = [NSArray
arrayWithObjects:treeView, contentView, nil];
// Den SplitView anzeigen
[window addSubview:splitController.view];
[window makeKeyAndVisible];
// Das Aufräumen nicht vergessen
[treeView release];
[contentView release];
[splitController release];

Als Standardeinstellung verbirgt der SplitView den ersten View im Portrait-Modus. Möchte man auf Popover verzichten und in diesem Modus einen SplitView verwenden, lassen sich die Methode willAnimateRotationToInterfaceOrientation: duration: überschreiben und je nach Orientierung die Größen der Views anpassen. Will man den ersten View im Portrait-Modus nicht nur verbergen, sondern ihn als Popover anbieten, implementiert man das UISplitViewControllerDelegate-Protokoll, um auf SplitView-spezifische Ereignisse reagieren zu können.

Es sei nun ein Knopf in der Toolbar vorgesehen, der den TreeView anzeigt. Der Knopf soll nur sichtbar sein, wenn der TreeView sich nicht auf dem Display befindet. Alles Weitere wie die eigentliche Anzeige des TreeView im PopoverView erfolgt automatisch. Dazu legt man die Toolbar wie folgt mit einem Button an. (Um zukunftssicher zu sein, sollten der Button-Titel eigentlich internationalisiert und die Größenkonstanten nicht fix eingetragen sein, das Beispiel vernachlässigt das aber.) Eine Member-Variable für die Toolbar (UIToolbar *toolbar) muss dazu vorab angelegt werden.

// Tree View Controller wird nicht sichtbar =» Toolbar anzeigen
- (void)splitViewController:(UISplitViewController*)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem*)barButtonItem
forPopoverController:(UIPopoverController*)pc {


barButtonItem.title = @"Tree";
if (toolbar == NULL) {
toolbar = [[UIToolbar alloc]
initWithFrame:CGRectMake(0, 0, 1024, 44)];
[toolbar setItems:[NSArray arrayWithObject:barButtonItem] animated:YES];
}

// Toolbar dem Content View hinzufügen
UIViewController* contentController = [svc.viewControllers objectAtIndex:1];
[contentController.view addSubview:toolbar];
}

// Tree View wird angezeigt =» Toolbar verbergen
- (void)splitViewController:(UISplitViewController*)svc
willShowViewController:(UIViewController *)aViewController
invalidatingBarButtonItem:(UIBarButtonItem *)button {

// Toolbar entfernen
[toolbar removeFromSuperview];
}

Das iPad lässt sich an externe Displays anschließen. Über die UIScreen-Klasse kann man mit der screens-Klassenmethode abfragen, ob ein externes Display angeschlossen ist und welche Konfigurationen (availableModes-Eigenschaft) es anbietet. Mit einem Screen-Modus kann man einem Window-Objekt jetzt ein solches Fenster zuordnen, sodass es auf dem Display dargestellt wird.

Das neue SDK sieht die Möglichkeit vor, einen grafischen Context anzulegen, in den man PDF-Inhalte einfügen kann. Dabei benutzt man dieselben Funktionen, als würde man in einen graphischen Context (wie den Core Graphics Context der Quartz API des iPhone) auf dem Display zeichnen. Im Beispiel wird ein Text in ein PDF-Dokument geschrieben. Je nachdem wie viel Platz der Text benötigt, sind dafür mehrere Seiten anzulegen und dann die Seitenzahlen auf der Seite einzufügen.

// PDF Context erzeugen
UIGraphicsBeginPDFContextToFile(@”doc.pdf”, CGRectZero, nil);
// Text vorbereiten und CTFramesetter für Layout erzeugen
CFAttributedStringRef text =
CFAttributedStringCreate(NULL,
(CFStringRef)textView.text, NULL);
CTFramesetterRef framesetter =
CTFramesetterCreateWithAttributedString(currentText);
if (!framesetter)
return;
CFRange currentRange = CFRangeMake(0, 0);
BOOL done = NO;
// Schleife, solange der Text nicht vollständig gerendert wurde
while (currentRange.location !=
CFAttributedStringGetLength((CFAttributedStringRef)text)) {
// Neue Seite anlegen
UIGraphicsBeginPDFPageWithInfo(
CGRectMake(0, 0, 612, 792), nil);
// Seitenzahl einfügen
[self drawPageNumber:1];
// Text rendern, currentRange auf nächste Seite anpassen
currentRange = [self renderPageWithTextRange:currentRange
andFramesetter:framesetter];
}
// Context schließen und PDF-Dokument schreiben
UIGraphicsEndPDFContext();
// Aufräumen nicht vergessen
CFRelease(currentText);
CFRelease(framesetter);

Wer für das iPhone programmiert hat, musste teils mühsam die Touch-Events auswerten, um Gesten zu erkennen, die eine App einem Benutzer angeboten hat. Die jetzt eingeführten Gesten-Erkenner (Gesture Recognizer Objekte) kapseln den Code, der zum Erkennen einer Geste verantwortlich ist, und lassen sich an Views und Aktionen koppeln. Während das Framework bereits Standard-Recognizer zur Rotation, zum Streichen et cetera vorsieht, lassen sich selbstdefinierte Gesten über Subklassen implementieren.

Schaut man sich die Recognizer genauer an, findet man einen Zustandsautomaten, der zwischen diskreten und fortdauernden Gesten unterscheidet und je nachdem andere Zustände durchlaufen kann. Wichtige Zustände sind "Geste möglich", "Geste abgebrochen" und "Geste erkannt". Bei eigenen Recognizern überschreibt man die Methoden, die bei Berührungen mit Touch-Events aufgerufen werden, und ändert den momentanen Zustand des Recognizer.

Gesture Recognizer lassen sich instanziieren und mit der gewünschten Aktion konfigurieren (als ein Objekt mit einer Callback-Methode, die gerufen wird, wenn eine Geste erkannt wurde).

UITapGestureRecognizer *myGesture =
[[UITapGestureRecognizer alloc]
initWithTarget:targetObj
action:@selector(handleDoubleDoubleTap:)];
[view addGestureRecognizer:myGesture];

Die Recognizer sind Beobachter für Touch-Events des View und nicht Teil der eigentlichen Kette von zur Verarbeitung von Ereignissen verantwortlichen Objekten (Responder Chain). Hat ein Recognizer eine Geste erkannt, werden die zugehörigen Touch-Events standardmäßig nicht mehr an den View geleitet. Auch können solche Events am View verzögert eintreffen, wenn der Gesture Recognizer sie noch verarbeitet.

Eine App kann angeben, dass sie bestimmte Dateitypen verarbeiten kann. Das ermöglicht es anderen Anwendungen, auf diese App zurückzugreifen, wenn sie einem Nutzer Aktionen zu einem Dokument anbieten möchte. Beispielsweise kann eine solche Aktion sein, das Dokument mit einer anderen Anwendung zu öffnen oder eine E-Mail mit dem Dokument als Anhang zu versenden. Die E-Mail-Anwendung kann so andere Apps für die Anzeige von Anhängen nutzen.

Die Registrierung der unterstützten Dateitypen geschieht über einen Eintrag in der plist-Datei der Anwendung (in dieser XML-Datei finden sich die Applikationseinstellungen). Eine App muss dann die Methode application:didFinishLaunchingWithOptions: im ApplicationDelegate (zentrale Klasse einer Anwendung, die Applikations-Events verarbeitet und den Lebenszyklus der App steuert) implementieren, damit sie sich mit der Angabe einer Datei aufrufen lässt. Dabei können Applikationen nicht nur die Datei, sondern auch zusätzliche Angaben beim Aufruf austauschen.

Außerdem lassen sich für die Apps unbekannte Dateitypen, die aber andere Anwendungen oder das Framework öffnen können, als Preview und Menüs mit möglichen Operationen anzeigen. Dazu erzeugt man eine Instanz der Klasse UIDocumentInteractionController für die gewünschte Datei. Die Instanz besitzt Eigenschaften zur Abfrage von Dateiinformationen, UIImage-Bilder-Objekte mit Icons der Datei in mehreren Größen und Methoden, um die Vorschau oder die Menüs darzustellen. Mit einem Methodenaufruf erhält dann der Nutzer ein Menü, mit dem er zum Beispiel direkt zu einer anderen, diese Datei unterstützenden Applikation wechseln kann.

Für mehr Datenaustausch zwischen App und Desktop gibt es jetzt pro Anwendung ein Datei-Austauschverzeichnis zwischen dem mobilen Gerät und dem Desktop-Rechner. Dabei kann eine App nur auf das eigene Verzeichnis zugreifen.

Apple hat im neuen Framework für das iPad insbesondere Wert auf Funktionen gelegt, die helfen, für ein solches Gerät optimierte Oberflächen zu schaffen. Gerade das dürfte die Welt der Tablet-PCs beleben. Denn genau an der Stelle muss jeder Entwickler umdenken: Man erstellt hier keine Programme, die sonst auf dem Desktop laufen und sich wie mit einer Maus bloß mit dem Finger bedienen lassen. Das iPad ist kein Ersatz für ein Notebook, es wird anders genutzt werden. Auch wenn die Hardware im Einzelnen nichts Neues ist, in der Gesamtheit zwingt es zum Umdenken.

Oliver Szymanski
ist als als Softwarearchitekt, Berater und Trainer für Java, .NET und mobile Entwicklungen tätig. Parallel dazu arbeitet er als Schriftsteller.
(ane [3])


URL dieses Artikels:
https://www.heise.de/-1009808

Links in diesem Artikel:
[1] http://www.apple.com/de/ipad/specs/
[2] http://www.apple.com/de/ipad
[3] mailto:ane@heise.de