5.2Layoutanpassungen und Viewrotationen
Im dritten Kapitel, »Sehen und anfassen«, haben Sie mit dem Autosizing und dem Autolayout bereits Möglichkeiten kennengelernt, die Position und die Größe Ihrer Views bei Geräterotationen und Größenänderungen des jeweiligen Superviews automatisch anzupassen. Die Klasse UIView stellt zusätzlich Methoden bereit, mit denen Sie ein beliebiges Layout umsetzen können. Dabei bestimmt jeweils der Superview die Position und Größe seiner Subviews. Sie können das verändern, indem Sie die Methode layoutSubviews überschreiben und darin die Subviews über deren Property frame so positionieren, wie Sie es wünschen. Das iOS ruft diese Methode auf, sobald der View ein neues Layout benötigt. Sie sollten diese Methode jedoch niemals direkt aufrufen. Falls Sie das Layout eines Views neu berechnen möchten, sollten Sie stattdessen setNeedsLayout verwenden.
Dabei gibt es Apps, wie beispielsweise Safari, die einfach nur die Größe der Views bei einer Geräterotation anpassen, oder solche wie den Rechner, der im Hochformat einen einfachen und im Querformat einen wissenschaftlichen Rechner anzeigt (siehe Abbildung 5.1).
Abbildung 5.1 Anpassung der Anzeige im Rechner
Das Fototagebuch soll seine Views auch automatisch an die Ausrichtung des Gerätes anpassen. Dazu müssen Sie allerdings keine Rotationen berechnen oder unterschiedliche Layouts verwalten. Es reicht aus, die Views größenunabhängig zu gestalten.
Größenanpassungen im Interface Builder
Im Interface Builder überprüfen Sie Ihre Einstellungen des Autosizings, indem Sie den Attributinspektor des Viewcontrollers öffnen. Dort befindet sich das Dropdown-Menü Orientation, mit dem Sie die Ausrichtung des Views verändern. Sie können dort auch in der Rubrik Simulated Metrics verschiedene System-UI-Elemente konfigurieren, um die verfügbare Fläche des Views anzupassen. Auch wenn Ihr View keine Rotation unterstützen soll, ist es immer eine gute Idee, seine Flexibilität über dieses Dropdown-Menü zu testen. Sie können damit recht einfach herausfinden, ob sich Ihr View richtig an neue Größen anpasst.
Die Einstellungen, die Sie dort vornehmen, haben jedoch keinen Einfluss auf Ihr Programm. Cocoa Touch passt den View immer an die aktuelle Viewausrichtung Ihrer App an.
5.2.1Lang lebe das Rotationsprinzip!

Zunächst müssen Sie jedoch Cocoa Touch mitteilen, für welche Geräteausrichtungen es die Views anpassen soll, denn häufig ist das nicht sinnvoll oder erwünscht. Beispielsweise unterstützen viele Spiele nur das Querformat, während z. B. das Game Center nur das Hochformat unterstützt. Die Geräteausrichtung bezeichnet übrigens die physikalische Ausrichtung des Gerätes, und Sie können sie über die Klasse UIDevice abfragen:
UIDeviceOrientation theOrientation =
[[UIDevice currentDevice] orientation];
Listing 5.7 Geräteausrichtung abfragen
Die Anzeigeausrichtung beschreibt hingegen die Ausrichtung des angezeigten Views. Die Anzeigeausrichtung ist also abhängig vom Viewcontroller und muss nicht mit der Geräteausrichtung übereinstimmen. Sie können die Anzeigeausrichtung des Viewcontrollers über seine Methode interfaceOrientation abfragen. Allerdings verwendet diese Methode den Rückgabetyp UIInterfaceOrientation, der andere Konstanten als UIDeviceOrientation besitzt.
Tabelle 5.1 listet alle Konstanten für die Geräte- und Anzeigeausrichtungen auf. Dabei hat Apple allerdings die Bezeichnungen für das Querformat vertauscht, also UIDeviceOrientationLandscapeLeft entspricht beispielsweise nicht UIInterfaceOrientationLandscapeLeft, sondern UIInterfaceOrientationLandscapeRight.
UIDeviceOrientation- | UIInterfaceOrientation- | Lage des Home-Buttons |
Portrait |
Portrait |
unten |
PortraitUpsideDown |
PortraitUpsideDown |
oben |
LandscapeLeft |
LandscapeRight |
links |
LandscapeRight |
LandscapeLeft |
rechts |
Über die Target-Einstellungen können Sie festlegen, welche Anzeigeausrichtungen die App prinzipiell unterstützt. Unter Device Orientation in der Rubrik Deployment Info wählen Sie die Geräteausrichtungen aus, für die Cocoa Touch die Views der App anpassen soll (siehe Abbildung 5.2); die Bezeichnungen in den Einstellungen entsprechen also der linken Spalte in Tabelle 5.1.
Abbildung 5.2 Unterstützte Geräteausrichtungen der App festlegen
Sie können die prinzipiellen Anzeigeausrichtungen auch über die Methode application:supportedInterfaceOrientationsForWindow: festlegen, die eine Bitmaske mit den unterstützten Anzeigeausrichtungen zurückliefert. Wenn die App beispielsweise nur das Querformat unterstützt, können Sie die Methode folgendermaßen implementieren:
- (NSUInteger)application:(UIApplication *)inApplication
supportedInterfaceOrientationsForWindow:
(UIWindow *)inWindow {
return UIInterfaceOrientationMaskLandscapeLeft |
UIInterfaceOrientationMaskLandscapeRight;
}
Listing 5.8 Unterstützte Anzeigeausrichtungen der App festlegen
Projektinformation
Zu diesem Beispiel finden Sie auf der DVD unter Code/Apps/iOS6/Rotation oder im Github-Repository zum Buch im Unterverzeichnis https://github.com/Cocoaneheads/iPhone/tree/Auflage_3/Apps/iOS6/Rotation ein Beispiel, das die dargestellte Größenanpassung veranschaulicht.
Wenn Sie die App im Simulator starten und diesen über die Menüpunkte Hardware • Links drehen (+
) beziehungsweise Hardware • Rechts drehen (
+
) drehen, rotiert der View in Abhängigkeit von den voreingestellten Werten mit und
passt sich der Ausrichtung an. Jeder Viewcontroller kann auch seine unterstützten
Anzeigeausrichtungen selbst festlegen.
Dazu implementieren Sie die Methode supportedInterfaceOrientations, die eine Bitmaske wie die Methode application:supportedInterfaceOrientationsForWindow: zurückliefert. Die Standardimplementierung liefert auf einem iPhone den Wert , d. h. alle Ausrichtungen außer der mit dem Home-Button oben. Auf dem iPad liefert die Methode hingegen UIInterfaceOrientationMaskAll; die Viewcontroller unterstützen hier also alle Geräteausrichtungen.
Außerdem können Sie über die Methode shouldAutorotate die automatische Anpassung an die Geräteausrichtung generell ausschalten.
Autorotation und Navigationcontroller
Bei Viewcontrollern in einem Navigationsstapel ignoriert der Navigationcontroller die Maske des Viewcontrollers, wodurch der View im Hochformat bei obenliegendem Home-Button die falsche Ausrichtung hat. Sie können allerdings eine Unterklasse von UINavigationController erstellen, in der Sie die Methode supportedInterfaceOrientations folgendermaßen überschreiben:
-(NSUInteger)supportedInterfaceOrientations {
return [self.topViewController
supportedInterfaceOrientations];
}
Dadurch fragt der Navigationcontroller immer den aktuell angezeigten Viewcontroller nach den unterstützten Ausrichtungen.
Wenn Ihr Viewcontroller den Beginn oder das Ende einer Rotation mitbekommen soll, können Sie dafür die Methoden willRotateToInterfaceOrientation:duration: und didRotateFromInterfaceOrientation: überschreiben, die Cocoa Touch vor beziehungsweise nach einer Rotation aufruft.
5.2.2Anpassung des Layouts
Der View des Diary-Entry-Viewcontrollers des Fototagebuchs passt sich bei der Rotation
des Gerätes an dessen Ausrichtung an. Er stellt im Hochformat das Foto über dem Text
dar. Das Querformat ordnet beide Elemente nebeneinander an. Dieses Verhalten können
Sie nicht über die Autosizingmask oder das Autolayout erreichen. Dazu verwendet das
Programm eine eigene Unterklasse RotationView von UIView, die die Methode layoutSubviews überschreibt.
Projektinformation
Den Quellcode des Fototagebuchs finden Sie auf der DVD unter Code/Apps/iOS6/PhotoDiary oder im Github-Repository zum Buch im Unterverzeichnis https://github.com/Cocoaneheads/iPhone/tree/Auflage_3/Apps/iOS6/PhotoDiary.
Dieser View passt bei einer Rotation nur die Koordinaten seines zweiten Subviews an. Dafür verwendet das Programm einen Hilfs-View, den Abbildung 5.3 als graue Fläche darstellt. Der Text-View passt sein Layout über die Autosizingmask an und hat feste Abstände zu den Rändern seines Superviews und eine flexible Breite und Höhe.
Abbildung 5.3 Automatische Layoutanpasung
Der Rotationview muss zwei Fälle unterscheiden. In der vertikalen Ansicht ordnet er den Hilfs-View unter dem Bild an, wobei dieser die volle Breite einnimmt. In der horizontalen Ansicht weist er dem Hilfs-View hingegen die volle Höhe zu und ordnet ihn neben dem Bild an. Die Methode unterscheidet zwischen Hoch- und Querformat, indem sie die Breite ihres Views mit dessen Höhe vergleicht.
- (void)layoutSubviews {
[super layoutSubviews];
CGRect theFrame = self.bounds;
CGRect theFirstFrame =
[[self.subviews objectAtIndex:0] frame];
UIView *theSecondView = [self.subviews objectAtIndex:1];
CGRect theSecondFrame = theSecondView.frame;
if(CGRectGetWidth(theFrame) < CGRectGetHeight(theFrame)) {
theSecondFrame.origin.x = 0.0;
theSecondFrame.origin.y =
CGRectGetMaxY(theFirstFrame);
theSecondFrame.size.width = CGRectGetWidth(theFrame);
theSecondFrame.size.height =
CGRectGetHeight(theFrame) –
CGRectGetMaxY(theFirstFrame);
}
else {
theSecondFrame.origin.x =
CGRectGetMaxX(theFirstFrame);
theSecondFrame.origin.y = 0.0;
theSecondFrame.size.width =
CGRectGetWidth(theFrame) –
CGRectGetMaxX(theFirstFrame);
theSecondFrame.size.height =
CGRectGetHeight(theFrame);
}
theSecondView.frame = theSecondFrame;
}
Listing 5.9 Berechnung des Layouts für die Rotationsanpassung
Listing 5.9 stellt die komplette Methode für das Layout dar. Sie können die Methode layoutSubviews der Klasse UIView immer überschreiben, wenn Sie das Layout Ihrer Views über Ihren Programmcode anpassen möchten. Sie sollten das jedoch nur machen, wenn das automatische Layout über die Autosizingmask dafür nicht ausreicht.
Cocoa Touch ruft diese Methode auf, wenn eine Neuanordnung Ihrer Views notwendig ist. Wie wir bereits erwähnt haben, sollten Sie diese Methode niemals direkt aufrufen, sondern durch einen Aufruf der Methode setNeedsLayout den View für einen Aufruf markieren. Alternativ können Sie auch durch einen Aufruf von layoutIfNeeded ein sofortiges Anordnen Ihrer Views erzwingen.
Tipp
Sie können durch einen eigenen View, der die Methode layoutSubviews überschreibt, Ihre Views beliebig an die Geräteausrichtung anpassen. Dabei können Sie nicht nur die Anordnung der Subviews anpassen, sondern sie auch anzeigen oder verstecken lassen. Sie sollten allerdings keine Steuerungslogik (z. B. zum Laden von Daten) in diese Methode legen. Dafür ist ja die Controller-Schicht zuständig.
Alternativ können Sie die Layoutlogik auch im Viewcontroller in der Methode ansiedeln. Cocoa Touch informiert den Controller durch Aufrufe der Methoden viewWillLayoutSubviews und viewDidLayoutSubviews über die Layoutanpassungen seines Views.
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.