5.2 Layoutanpassungen und Viewrotationen
Zu den faszinierenden Neuerungen des iPhones gegenüber seinen Konkurrenzprodukten gehört sicherlich auch die Möglichkeit, das Gerät sowohl im Hoch- als auch im Querformat verwenden zu können. Sie drehen das iPhone um 90°, und die Bildschirmanzeige passt sich der neuen Ausrichtung automatisch an. Dabei gibt es Apps, wie beispielsweise Safari, die einfach nur das Layout anpassen, oder solche wie den Rechner, der im Hochformat einen einfachen und im Querformat einen wissenschaftlichen Rechner anzeigt (siehe Abbildung 5.1). In Kapitel 4, »Alles unter Kontrolle«, haben Sie bereits Möglichkeiten kennengelernt, wie Sie das Rotationsverhalten in Ihrer Applikation beeinflussen können.
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, wenn Sie Ihre Views größenunabhängig gestalten.
5.2.1 Flexible Views dank Autosizing

Jeder View besitzt eine eigene Autoresizingmask. Sie besteht aus sechs booleschen Werten, die zu einer Bitmaske verknüpft sind. Die booleschen Werte stehen dabei für die Veränderlichkeit – entweder für einen Abstand zu den vier Seiten des umliegenden Views oder für die Breite beziehungsweise Höhe des Views.
Autosizing und Xcode 4.5
Xcode verwendet ab der Version 4.5 standardmäßig Autolayouts (siehe Abschnitt 5.3) in Storyboards und XIB-Dateien. Damit Sie Autosizing [ [Apple verwendet im Interface Builder die Bezeichnung »Autosizing«, während die Methodennamen »Autoresizing« enthalten.] verwenden können, müssen Sie im Dateiinspektor der Interfacedatei in der Rubrik Interface Builder Document den Haken bei Use Autolayout deaktivieren (siehe Abbildung 5.2). Wenn Ihre App auch mit iOS 5.1 oder früher kompatibel sein soll, sollten Sie das Autolayout auf jeden Fall ausschalten.
Abbildung 5.2 Autolayout im Inspektor der XIB-Datei ausschalten
Sie passen die Autosizingmaske über den Größeninspektor im Interface Builder an, der Ihnen dazu auch ein animiertes Beispiel anzeigt (siehe Abbildung 5.3), oder über die Property autoresizingMask im Code. Während die Anpassung im Code einheitlich ist – Sie setzen jeweils das Bit für die Größen, die flexibel sein sollen –, ist die Einstellung im Interface Builder für die Ränder im Gegensatz zu Breite und Höhe vertauscht. Sie müssen dort den roten Strich für ein Randelement selektieren, wenn es konstant sein soll, und Sie müssen es deselektieren, falls Sie es flexibel haben möchten. Bei der Breite und der Höhe ist es genau umgekehrt. Dort bedeutet ein selektierter Doppelpfeil, dass die Größe flexibel ist; und ein deselektierter Doppelpfeil bedeutet, dass die Größe fest ist.
Abbildung 5.3 Autosizing und Beispiel im Größeninspektor
Sie können die Maske aus der Abbildung also folgendermaßen im Programmcode setzen:
theView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleBottomMargin;
Listing 5.5 Setzen der Autoresizingmask im Programmcode
Tipp
Nutzen Sie die Beispielansicht im Interface Builder, wenn Sie sich unsicher sind, wie Sie das Autosizing für Ihre Anforderungen einstellen müssen. Die Animation verdeutlicht sehr schön, wie sich der View bei einer Größenänderung seines Superviews verändert.
Die Einstellungen in der Autoresizingmask eines Views werden immer dann wirksam, wenn sich die Größe des Superviews ändert. Wenn die Maske für eine Größe festlegt, dass sie unveränderlich ist, hat sie nach der Größenänderung den gleichen Wert wie davor. Definiert die Maske den Wert hingegen als veränderlich, so wird die Größe dynamisch angepasst.
Die folgenden Beispiele sollen das Verhalten veranschaulichen:
- Wenn Sie einem View eine flexible Breite und Höhe geben, hat der View immer den gleichen Abstand zu den Rändern seines Superviews. Sie können mit dieser Maske beispielsweise Rahmen mit einer festen Breite realisieren. Wenn Sie eine neue XIB-Datei anlegen, bekommt der darin enthaltene View diese Maske, damit sich dessen Größe bei einer Rotation automatisch an die Größe des Bildschirms anpassen kann.
- Wenn Sie Textfelder, Labels und Buttons im Interface Builder anlegen, bekommen diese einen flexiblen rechten und unteren Rand. Bei einer Größenveränderung des Superviews ändern sie also ihre Position zum linken und oberen Rand nicht. Das ist sinnvoll, da es allgemein üblich ist, Formulare von oben links her aufzubauen.
- Formulare zeigen in der Regel die Buttons zum Annehmen oder Ablehnen am unteren Rand an. Hier müssen Sie also den oberen Rand flexibel und den unteren unveränderlich setzen, damit die Buttons sich immer am unteren Rand ausrichten.
- Tabbars und Werkzeugleisten liegen am unteren Bildschirmrand und nehmen dessen komplette Breite ein. Sie müssen bei diesen Elementen also einen flexiblen oberen Rand und eine flexible Breite setzen, so wie es der Interface Builder bei diesen Elementen auch automatisch macht.
Tipp
Sie sollten Ihre Views möglichst so gestalten, dass sie flexibel auf Größenveränderungen reagieren. Zum einen kann der View in der App eine andere Größe als im Interface Builder haben, und zum anderen ist das die beste Voraussetzung, um dessen Rotationsfähigkeit sicherzustellen.
Sie sollten sich außerdem beim Anlegen eines Views nicht auf feste Display-Größen verlassen. Momentan haben beispielsweise alle iPhone- und iPod-touch-Displays eine Größe von 320 × 480 Punkten, was entweder der Pixelzahl oder auf Retina-Displays 640 × 960 Pixeln entspricht. Das neue iPhone 5 hat eine Auflösung von 320 × 568 Punkten beziehungsweise 640 × 1136 Pixeln. Wenn Sie den kompletten Bildschirm des iPhone 4(s) und des iPhone 5 ausnutzen wollen, sollten Sie Ihre Views also entsprechend flexibel gestalten.
Die Autoresizingmask ist eine relativ einfache und effektive Methode, um Views größenunabhängig gestalten zu können. Sie kann jedoch nicht alle Möglichkeiten abdecken. Beispielsweise sollte beim analogen Wecker das Ziffernblatt möglichst immer quadratisch sein. Das lässt sich durch die Autoresizingmask jedoch nicht ausdrücken, sondern nur über Programmcode oder Autolayouts.
Die Klasse UIView stellt jedoch 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.
5.2.2 Lang lebe das Rotationsprinzip!

Das Prinzip hinter der Rotation aus der Perspektive der App ist erstaunlich einfach, da es nur auf der Größenveränderung des dargestellten Views beruht. Die Verwaltung und die Darstellung der Rotation übernimmt das iOS für Sie. Sie brauchen also Ihren View nur größenunabhängig aufzubauen, um ihn rotationsfähig zu machen.
Abbildung 5.4 Layoutanpassung bei Rotation über die Autoresizingmask
Sie können dafür in vielen Fällen die Autoresizingmask verwenden, wenn die Größe
- sich durch die Rotation nicht verändern soll oder
- nur von der entsprechenden Größe des umgebenden Views in der gleichen Dimension abhängt.
Es lässt sich also beispielsweise die Breite des Views über die Autoresizingmask dynamisch anpassen, wenn die neue Breite nach der Rotation nur von der neuen Breite des Superviews abhängt. Abbildung 5.4 zeigt dafür ein Beispiel für eine solche Rotationsanpassung mit festen und variablen Größenänderungen. In der Darstellung entspricht der linke View der Darstellung im Hochformat und der rechte View der Darstellung im Querformat. Die weißen Punkte bedeuten, dass der entsprechende Randwert in der Maske fixiert ist, und die gestrichelten Pfeile bedeuten, dass der entsprechende Größenwert in der Maske flexibel ist.
Projektinformation
Zu diesem Beispiel finden Sie auf der DVD unter Code/Apps/Rotation oder im Github-Repository zum Buch im Unterverzeichnis https://github.com/Cocoaneheads/iPhone/tree/Auflage_2/Apps/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 allerdings noch mit und passt sich der Ausrichtung nicht
an. Das liegt daran, dass Sie Cocoa Touch noch nicht mitgeteilt haben, welche Ausrichtungen
der View unterstützt. Dazu müssen Sie bis iOS 5 die Methode shouldAutorotateToInterfaceOrientation: des Viewcontrollers implementieren, die Sie bereits in Kapitel 4, »Alles unter Kontrolle«, kennengelernt haben. Sie bekommt vom iOS die gewünschte
Ausrichtung als Parameter übergeben und liefert YES zurück, wenn der View, den der Controller verwaltet, diese Ausrichtung unterstützt.
Ab iOS 6 implementieren Sie stattdessen shouldAutorotate und supportedInterfaceOrientations. Dabei gibt die erste Methode an, ob der View rotieren darf, und die zweite legt
fest, welche Ausrichtungen er unterstützt. Der View passt sich also nur der Geräteausrichtung
an, wenn shouldAutorotate als Ergebnis YES liefert.
Autorotation und Navigationcontroller
Bei Viewcontrollern in einem Navigationsstapel ignoriert der Navigationcontroller die Maske des Viewcontrollers, wodurch der View im Hochformat bei oben liegendem Homebutton 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.
In der Beispiel-App können Sie den Rückgabewert dieser Methode über das Segmentedcontrol oben rechts steuern. Wenn Sie es auf An stellen, liefert die Methode den Wert YES, und der View passt sich der Ausrichtung des Gerätes an.
Größenanpassungen im Interface Builder
Im Interface Builder können Sie Ihre Einstellungen des Autosizings überprüfen, indem Sie den Attributinspektor des Viewcontrollers oder des obersten Views öffnen. Dort befindet sich das Dropdown-Menü Orientation, mit dem Sie die Ausrichtung des Views verändern können. 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, dessen 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.
Wenn sie also beispielsweise im Hochformat den View mit den Abmessungen des Querformats anzeigt, sollten Sie die Autoresizingmask [beziehungsweise die Restriktionen des Autolayouts (siehe Abschnitt Autolayout)] und die Einstellung Resize View From NIB im Attributinspektor des Viewcontrollers überprüfen. Sollte sich hingegen Ihr View mit dem Gerät mitdrehen, so liegt das am Rückgabewert der Methoden für die Rotation (siehe Kapitel 4, »Alles unter Kontrolle«).
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.
Die aktuelle Viewausrichtung des Viewcontrollers können Sie über die Property interfaceOrientation auslesen. Dieser Wert entspricht dabei der Anzeige- und nicht der Geräteausrichtung. Das sind zwei unterschiedliche Werte, da ja die Anzeigeausrichtung nicht der Geräteausrichtung entsprechen muss. Wenn Ihr Viewcontroller beispielsweise nur das Hochformat unterstützt, bleibt die Anzeigeausrichtung immer gleich, egal wie Sie das Gerät drehen und dabei die Geräteausrichtung ändern.
Die Geräteausrichtung können Sie über die Property orientation des Singletons UIDevice ermitteln. Die Device-Klasse verwendet zwar andere Konstanten, die für das Querformat auch noch vertauschte Bezeichnungen – Links ist das neue Rechts – haben. Sie können jedoch die Rückgabewerte der beiden Propertys trotzdem miteinander vergleichen, da Cocoa Touch die UIInterfaceOrientation-Konstanten über die Device-Konstanten definiert.
Achtung
Wenn Sie die zulässige Ausrichtung des Viewcontrollers von der aktuellen Ausrichtung des Gerätes abhängig machen möchten, dürfen Sie in shouldAutorotateToInterfaceOrientation: nicht die Property interfaceOrientation des Viewcontrollers verwenden. Diese Property liefert Ihnen nicht die Ausrichtung des Gerätes, sondern die des Viewcontrollers. Die Verwendung dieser Property kann an dieser Stelle zu einer Endlosrekursion führen. Wenn Sie die Geräteausrichtung ermitteln möchten, sollten Sie immer die Property orientation der Klasse UIDevice verwenden.
5.2.3 Anpassung des Layouts
![]()
Der View des Itemviewcontrollers 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 Autoresizingmask erreichen. Dazu verwendet das Programm eine eigene Unterklasse RotationView von UIView, die die Methode layoutSubviews überscheibt.
Projektinformation
Den Quellcode des Fototagebuchs finden Sie auf der DVD unter Code/Apps/PhotoDiary oder im Github-Repository zum Buch im Unterverzeichnis https://github.com/Cocoaneheads/iPhone/tree/Auflage_2/Apps/PhotoDiary.
Dieser View passt bei einer Rotation nur die Koordinaten seines zweiten Subviews an. Dafür verwendet das Programm einen Hilfsview, den Abbildung 5.5 als graue Fläche darstellt. Der Textview passt sein Layout über die Autoresizingmask an und hat feste Abstände zu den Rändern seines Superviews und eine flexible Breite und Höhe.
Abbildung 5.5 Automatische Layoutanpasung
Der Rotation-View muss zwei Fälle unterscheiden. In der vertikalen Ansicht ordnet er den Hilfsview unter dem Bild an, wobei dieser die volle Breite einnimmt. In der horizontalen Ansicht weist er dem Hilfsview 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.frame;
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.6 Berechnung des Layouts für die Rotationsanpassung
Listing 5.6 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 hingegen nur machen, wenn das automatische Layout über die Autoresizingmask dafür nicht ausreicht.
Cocoa Touch ruft diese Methode auf, wenn eine Neuanordnung Ihrer Views notwendig ist. Wie bereits erwähnt wurde, sollten Sie diese Methode niemals direkt aufrufen, sondern durch einen Aufruf der Methode setNeedsLayout Ihren 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 die Controllerschicht zuständig.
Ab iOS 5 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.
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.









Jetzt bestellen





