4.6Der Page-Viewcontroller
Eine weitere Möglichkeit, zwischen den Viewcontrollern einer App zu navigieren, ist eine Wischnavigation, bei der Sie auf dem Bildschirm nach rechts oder links streichen, um zur vorherigen oder nächsten Seite zu gelangen. Mit der Klasse UIPageViewController steht ein Container-Viewcontroller zur Verfügung, der das Blättern zwischen beliebig vielen Viewcontrollern erlaubt. Er animiert dabei den Wechsel durch eine Blätteranimation, die das Umschlagen einer Buchseite (horizontales Blättern) oder eines Kalenderblattes (vertikales Blättern) nachahmt. Seit iOS 6 gibt es außerdem eine Scroll-Animation. Sie können bei der Blätteranimation eine von drei möglichen Achsen wählen:
- UIPageViewControllerSpineLocationMin: der linke oder obere Rand des Views
- UIPageViewControllerSpineLocationMid: die horizontale oder vertikale Mittelachse des Views
- UIPageViewControllerSpineLocationMax: der rechte oder untere Rand des Views
Ein- und doppelseitige Darstellung
Die doppelseitige Darstellung des Page-Viewcontrollers eignet sich in der Regel nur im Querformat beim horizontalen Blättern oder im Hochformat beim vertikalen Blättern. Über die Delegate-Methode pageViewController:spineLocationForInterfaceOrientation: können Sie die Bezugsposition für das Blättern bei einer Viewrotation ändern.
Wenn der Page-Viewcontroller eine Mittelachse als Bezug verwendet, stellt er immer zwei Viewcontroller gleichzeitig dar, ansonsten nur einen. In diesem Fall können Sie eine doppelseitige Darstellung über die Property doubleSided wählen. Dann verwendet der Page-Viewcontroller jeden zweiten Controller zur Darstellung der Rückseite seines jeweiligen Vorgängers.
Bei der einseitigen Darstellung verwendet der Page-Viewcontroller hingegen ein stark aufgehelltes, gespiegeltes Abbild der ungeraden Seiten für die Rückseiten.
Die Kehrseite der Medaille
Verwenden Sie die doppelseitige Darstellung nur mit der Curl-Animation; sie ergibt nicht nur bei der Scroll-Animation keinen Sinn, sondern kann sogar zu Abstürzen führen.
4.6.1Einen Page-Viewcontroller erzeugen

Sie können einen Page-Viewcontroller sowohl über Programmanweisungen als auch über ein Storyboard anlegen. Falls Sie den letztgenannten Weg wählen, müssen Sie dem Page-Viewcontroller jedoch nach der Erzeugung seine initialen Subviewcontroller per Programmcode zuweisen; außerdem ist in der Regel die Zuweisung des Delegates und der Datenquelle notwendig. Dabei ist die Datenquelle eine Controller-Komponente, die dem Page-Viewcontroller die Subviewcontroller für das Blättern zur Verfügung stellt.
Datenquellen
Eine Datenquelle ist eine Controller-Komponente, die Objekte für einen anderen Controller bereitstellt. Dabei fragt der Controller die Datenquelle immer nur nach den Daten, die er aktuell benötigt, und er überlässt die Verwaltung der Daten komplett der Datenquelle. Dieses Vorgehen hat den Vorteil, dass die Applikation nicht die kompletten Daten im Hauptspeicher halten muss. Der Controller kann also riesige Datenmengen bei verhältnismäßig geringem Speicherverbrauch anzeigen.
Bei der Konstruktion eines Page-Viewcontrollers legen Sie die Richtung und die Animation des Blätterns fest. Diese Werte können Sie später nicht mehr ändern. Als Animationstyp steht bis iOS 5 nur UIPageViewControllerTransitionStylePageCurl zur Verfügung, der ein Umblättern der Seiten simuliert. Ab iOS 6 gibt es außerdem den Typ UIPageViewControllerTransitionStyleScroll, der die Seiten von den Rändern her hineinschiebt.
Projektinformation
Den Quellcode des folgenden Beispielprojekts finden Sie auf der DVD unter Code/Apps/iOS6/Page oder im Github-Repository zum Buch im Unterverzeichnis https://github.com/Cocoaneheads/iPhone/tree/Auflage_3/Apps/iOS6/Page.
Mit dem Beispielprojekt Page, das Sie auf der beiliegenden DVD finden, können Sie die verschiedenen Einstellungen eines Page-Viewcontrollers ausprobieren. Es erzeugt den Controller über den in Listing 4.48 dargestellten Code.
UIPageViewControllerNavigationOrientation theOrientation =
self.selectedNavigationOrientation;
UIPageViewControllerSpineLocation theLocation =
self.selectedSpineLocation;
BOOL isDoubleSided =
self.doubleSidedControl.selectedSegmentIndex;
NSDictionary *theOptions = @{
UIPageViewControllerOptionSpineLocationKey :
@(theLocation) };
UIPageViewController *theController =
[[UIPageViewController alloc] initWithTransitionStyle:
self.animationControl.selectedSegmentIndex
navigationOrientation:theOrientation
options:theOptions];
NSArray *theControllers =
[self viewControllersForSpineLocation:theLocation];
theController.doubleSided = isDoubleSided ||
theLocation == UIPageViewControllerSpineLocationMid;
theController.dataSource = self;
theController.delegate = self;
[theController setViewControllers:theControllers
direction:self.selectedDirection animated:YES
completion:NULL];
Listing 4.48 Erzeugen eines Page-Viewcontrollers
Die Bezugsposition für das Blättern übergeben Sie in einem Dictionary unter dem Schlüssel UIPageViewControllerOptionSpineLocationKey. Allerdings dürfen Sie bei der mittleren Blätterposition nur die doppelseitige Darstellung angeben. Außerdem müssen Sie die Viewcontroller setzen, die der Page-Viewcontroller nach seinem Erscheinen anzeigen soll. Auch hier ist die mittlere Blätterposition ein Sonderfall, da das Array hier zwei Viewcontroller enthalten muss. Für die anderen Positionen darf das Array hingegen immer nur ein Element enthalten. Die Werte für diese Konfigurationsoptionen fasst Tabelle 4.7 noch einmal zusammen.
Blätterposition | Rückseitendarstellung | Anzahl Viewcontroller |
Minimum |
Ein- und doppelseitig |
1 |
Mitte |
Doppelseitig |
2 |
Maximum |
Ein- und doppelseitig |
1 |
Listing 4.48 verwendet eine Hilfsmethode, um die Viewcontroller für die Konstruktion zu erzeugen. Die Methode viewControllersForSpineLocation: liefert ein Array mit so vielen Viewcontrollern zurück, wie in Tabelle 4.7 angegeben sind. Dieses Array übergeben Sie über die Methode setViewControllers:direction:animated:completion: an den Page-Viewcontroller. Dabei sind die weiteren Parameter nur für bereits angezeigte Controller relevant. Über den Parameter animated legen Sie fest, dass die neuen Seiten durch ein Umblättern erscheinen. Die Richtung des Blätterns können Sie über den Parameter direction festlegen. Der letzte Parameter kann eine Blockfunktion enthalten, die der Controller nach Beendigung der Animation aufruft.
4.6.2Die Datenquelle und das Delegate
Für das Blättern müssen Sie dem Page-Viewcontroller jeweils die benötigten Viewcontroller für die Seiten über eine Datenquelle mit dem Protokoll UIPageViewControllerDataSource bereitstellen. Es deklariert die zwei notwendigen Methoden pageViewController:viewControllerBeforeViewController: und pageViewController:viewControllerAfterViewController:, mit denen der Page-Viewcontroller jeweils auf die Vorgänger beziehungsweise Nachfolger eines Viewcontrollers zugreifen kann. Das Beispielprogramm verwendet für die Seiten einfach Viewcontroller, die eine Seitenzahl anzeigen. Die Methoden der Datenquelle erzeugen jeweils einen neuen Viewcontroller, bei dem die Seitennummer um eins niedriger beziehungsweise höher ist. Listing 4.49 enthält die Methode der Datenquelle zur Bestimmung des Vorgängers. Die Implementierung für die Bestimmung der Nachfolger ist dabei bis auf die vorletzte Zeile (+ anstatt –) gleich.
- (UIViewController *)pageViewController:
(UIPageViewController *)inPageViewController
viewControllerBeforeViewController:
(UIViewController *)inViewController {
LabelViewController *theController =
(LabelViewController *)inViewController;
return [self labelViewControllerWithPageNumber:
theController.pageNumber – 1];
}
Listing 4.49 Erzeugung des Vorgängers in der Datenquelle
Der Viewcontroller für die Seiten stammt aus dem Storyboard, und die App erzeugt ein neues Objekt jeweils über die Methode instantiateViewControllerWithIdentifier:.
- (id)labelViewControllerWithPageNumber:(NSInteger)inPage {
LabelViewController *theController = [self.storyboard
instantiateViewControllerWithIdentifier:@"label"];
theController.pageNumber = inPage;
return theController;
}
Listing 4.50 Erzeugung eines Viewcontrollers aus dem Storyboard
Der Page-Viewcontroller kann bei einer Gerätedrehung die Blätterposition über die Delegate-Methode pageViewController:spineLocationForInterfaceOrientation: des Protokolls UIPageViewControllerDelegate ändern. Eine Änderung ist in der Regel bei der mittleren Blätterachse sinnvoll, da beispielsweise im Hochformat das horizontale Blättern zu zwei sehr schmalen Views führt. Wenn Sie die Blätterachse über diese Methode ändern, müssen Sie gegebenenfalls die Anzahl der Subviewcontroller im Page-Viewcontroller aktualisieren. In der Beispiel-App Page können Sie dieses Verhalten über den Schalter Update spine location on rotation beeinflussen, und die entsprechende Implementierung der Methode pageViewController:spineLocationForInterfaceOrientation: finden Sie in Listing 4.51:
- (UIPageViewControllerSpineLocation)pageViewController:
(UIPageViewController *)inPageViewController
spineLocationForInterfaceOrientation:
(UIInterfaceOrientation)inOrientation {
UIPageViewControllerSpineLocation theLocation =
self.selectedSpineLocation;
if(self.updateLocationSwitch.on) {
BOOL isHorizontal =
self.selectedNavigationOrientation ==
UIPageViewControllerNavigationOrientationHorizontal;
NSArray *theControllers;
if(theLocation ==
UIPageViewControllerSpineLocationMid &&
UIInterfaceOrientationIsLandscape(inOrientation)
!= isHorizontal) {
theLocation =
UIPageViewControllerSpineLocationMin;
}
theControllers = [self
viewControllersForSpineLocation:theLocation];
[inPageViewController setViewControllers:
theControllers direction:self.selectedDirection
animated:YES completion:NULL];
}
return theLocation;
}
Listing 4.51 Berechnung der Blätterposition für die Viewrotation
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.