5. August 2019

Auto Layout: Positionierung mit Layout-Constraints

Mit Layout-Constraints können Views regelbasiert positioniert werden. Damit kann eine Ausrichtung für die unterschiedlichen Bildschirmauflösungen und für die Darstellung im Hoch- und Querformat realisiert werden. Sie vereinfachen auch die Wiederverwendung von Views, denn flexibel positioniert könnten zum Beispiel für das iPhone entwickelte Screens als Teil eines iPad-Screens verwendet werden. Zudem sind sie sehr hilfreich für mehrsprachige Apps, bei denen die Texte je nach Sprache unterschiedlich viel Platz benötigen.

Funktionsweise von Layout Constraints

Die frame-Eigenschaft eines UIView-Objektes legt die Position und Größe des Views fest. Dabei wird das View relativ zu dem beinhaltenden superview positioniert. Hierbei kann lediglich über die Eigenschaft autoresizingMask auf die Größe des umgebenden Views Bezug genommen werden und z.B. eine automatische Größenskalierung mit dem umgebenden View erreicht werden. Von dieser Möglichkeit wird jedoch seit der Einführung der Layout Contraints in iOS 6 nur noch selten Gebrauch gemacht.

Layout Constraints sind Regeln, die die Positionierung eines Views beschreiben, z.B.:

Layout Contraint

  • nach rechts 20pt Abstand zur folgenden Bildschirmkante
  • nach links 20pt Abstand zur vorausgehenden Bildschirmkante
  • nach oben 35pt Abstand zur Bildschirmkante/Status-Bar

Solche Layout-Regeln können im Storyboard Editor grafisch definiert werden:

Layout Constraint

Dabei wird immer eine Beziehung zwischen zwei Elementen hergestellt: Im Beispiel wird die linke/vorausgehende Kante des Buttons (Button.Leading) mit der linken Kante des Superviews (Superview.Leading) gleichgesetzt (Equal) und dabei mit Constant ein Abstand von 20 Punkt festgelegt. Alle definierten Regeln bilden ein Gleichungssystem, welches gelöst wird um eine Positionierung zu finden, die alle Constraints erfüllt. Das bedeutet auch, dass Constraints gleichberechtigt sind und, sofern keine Prioritäten definiert werden, keine bestimmte Reihenfolge haben, in der sie zur Anwendung kommen.

Im obigen Beispiel ist mit den drei Regeln die Positionierung des Buttons vollständig beschrieben: Die Höhe des Buttons ergibt sich automatisch aus der Größe des Button-Textes (intrinsic content size), da dafür kein expliziter Constraint angelegt wurde.

Zur Laufzeit führt die Anwendung der Layout Constraints dazu, dass den Views die jeweilige Position und Größe als frame gesetzt wird.

Constraints im Interface Builder erstellen

Da sich die Layout-Regeln nicht in jedem Fall aus der Positionierung von Steuerelementen ableiten lassen, müssen Layouts-Constraints explizit erstellt und konfiguriert werden. Dazu gibt es drei verschiedene Möglichkeiten:

Constraints erstellen: Automatisches Beheben von Layout-Problemen

Mit Add Missing Constraints bzw. Reset to Suggested Constraints im Resolve Auto Layout Issues-Menü werden automatisch Constraints anhand der aktuellen Positionierung abgeleitet:

Resolve Auto Layout Issues: Reset to Suggested Constraints

So erstellte Constraints sind ein möglicher Ausgangspunkt, müssen aber meist manuell nachgebessert werden, da sich Layout-Regeln häufig nicht korrekt aus einer bestimmten Positionierung ableiten lassen.

Constraints erstellen: Constraints mit der rechten Maustaste ziehen

Alternativ können Layout-Constraints erstellt werden, indem man mit gedrückter rechter Maustaste (bzw. gedrückter Ctrl-Taste) von dem auszurichtendem View zieht auf das View, an dem sich die Ausrichtung orientieren soll. Dabei spielt die Richtung eine Rolle - zieht man nach links oder rechts werden Constraints zur horizontalen Ausrichtung angeboten, zieht man nach oben oder unten werden Constraints zur vertikalen Ausrichtung angeboten, zieht man schräg, werden beide Richtungen angeboten:

Constraints mit der rechten Maustaste ziehen

Existiert bereits eine entsprechende Regel, wird in dem Menü ein Punkt vor dem Constraint angezeigt. Mit gedrückter Shift-Taste können mehrere Constraints auf einmal angelegt werden:

Mehrere Constraints auf einmal anlegen

Constraints erstellen: Add New Constraints

Mit Add New Constraints können mehrere Layout-Regeln komfortabel auf einmal angelegt werden:

Constraints per Add New Constraints anlegen

Constraints konfigurieren und bearbeiten

Erstellte Constraints können im Interface Builder ausgewählt und konfiguriert werden. Dazu empfiehlt sich insbesondere die Constraints-Liste im Size Inspector. Hier werden alle Layout-Regeln, die für das ausgewählte View gelten, angezeigt:

Constraints im Interface Builder auswählen und bearbeiten

Wird die Positionierung verändert, nachdem Constraints erstellt wurden, werden die Constraints nicht automatisch angepasst. Interface Builder zeigt lediglich die Abweichung zwischen den aktuellen Frames und der Positionierung, die sich laut der Constraints ergeben würde, orange an:

Abweichung Positionierung laut Frames und laut Constraints

Mit Update Constraint Constants können die Constraints entsprechend angepasst werden. Alternativ kann mit Update Frames die Positionierung wieder in den Zustand laut Constraints zurückgesetzt werden:

Update Frames / Update Constraints

Das heißt: Die Frames/die Positionierung der Steuerelemente zur Design-Zeit und die Positionierung, die sich laut der Layout-Constraints ergeben würden, sind zwei verschiedene Dinge. Interface Builder zeigt Abweichungen zwischen den Frames und der Positionierung laut Layout-Constraints an und erlaubt die Constraints gemäß der Frames anzupassen und umgekehrt.

Layout-Probleme

Bei der Verwendung von Constraints können Probleme auftreten. Dies wird dadurch kenntlich gemacht, dass ein Layout-Problem in der Outline angezeigt wird. Hier fehlt beispielsweise ein Constraint der die Positionierung nach oben festlegt - die Layout-Constraints sind unterbestimmt:

Layout Problem: Unterbestimmte Layout-Constraints

Ein weiteres mögliches Problem sind überbestimmte Constraints - Regeln die sich mit anderen Regeln widersprechen. Diese werden rot angezeigt und weitere Informationen können über den Marker in der Outline abgerufen werden. Hier sind beispielsweise zwei sich widersprechende Layout-Regeln für den Abstand nach oben angelegt:

Layout-Probleme: Konflikte / Überbestimmte Constraints

Vorschau für verschiedene Gerätegrößen

Mit View as: ... kann im Storyboard die Gerätegröße und Drehung ausgewählt werden, mit der die Controller im Storyboard-Editor angezeigt werden:

Xcode Storyboard Preview

Alternativ kann über den Assistant Editor die Storyboard-Vorschau aktiviert werden. Diese erlaubt die parallele Anzeige für mehrere Bildschirmgrößen und Drehungen:

Storyboard-Vorschau im Assistant Editor

Tutorial 1: Einführung in die Verwendung von Layout-Constraints

  1. Erstelle für dieses Tutorial ein leeres Single View App-Xcode-Projekt oder füge einem bestehenden Storyboard einen neuen, leeren View-Controller hinzu. Platziere in der rechten, oberen Ecke des Views einen Button. Vergrößere diesen etwas und setze im Attributes Inspector eine Hintergrundfarbe:

    Neuer View-Controller mit Button
  2. Blende den Assistant Editor ein, aktiviere via Preview die Vorschau und füge mit dem +-Button links unten einige zusätzliche Gerätegrößen hinzu:

    Neuer View-Controller mit Button
  3. Aktuell erfolgt die Positionierung über die Frame-Eigenschaft mittels absoluter Angaben in Punkt, die Du im Size Inspector findest:

    Size Inspector
  4. Ziehe diagonal mit gedrückter rechter Maustaste (bzw. gedrückter ^-Taste) vom Button auf das umgebende View. Wähle mit gedrückter Shift-Taste (Mehrfachauswahl) Trailing Space to Safe Area und Top Space to Safe Area aus und bestätige die Auswahl mit Enter:

    Layout-Constraint erstellen

    Tipp: Durch das Ziehen in diagonaler Richtung werden sowohl Constraints in der horizontalen als auch vertikalen Richtung angeboten. Es ist auch möglich horizontal oder vertikal zu ziehen um nur Constraints in der einen Richtung angeboten zu bekommen:

    Diagonal/Horizontal/Vertikal ziehen

  5. Prüfe über die Outline, dass zwei Layout-Constraints erstellt wurden:

    Erstellte Constraints

    Wähle einen der Constraints aus und mache Dich mit den Eigenschaften im Size Inspector vertraut. Hier wird sichtbar, dass der Layout-Mechanismus von iOS auf dem Lösen von Gleichungssystemen basiert:

    Layout Constraints Size Inspector

    Hinweis: Die Reihenfolge von First und Second Item sind beliebig vertauschbar, da die Gleichungen entsprechend umgestellt werden können. Im Auswahlmenü findest Du dafür auch eine Option:

    Reverse First And Second Item

Tutorial 2: Layout-Constraints automatisch erstellen

  1. Lade den Start-Stand von dem Flashcards-Beispielprojekt: Flashcards.zip.
    Öffne das Storyboard und mache Dich mit den View-Controllern des Projektes vertraut. Die Darstellung der Lernkarte soll im Folgenden so mit Layout-Constraints versehen werden, dass die Darstellung für die jeweilige Bildschirmgröße und -drehung angepasst wird:

    Ergebnisse: Layout-Constraint Tutorial

  2. Öffne Main.storyboard und mache Dich mit den Layout-Buttons rechts unten vertraut:

    Layout-Buttons im Interface-Builder

  3. Wähle im Storyboard den CardViewController aus und prüfe, dass eine Anordnung wie oben abgebildet gegeben ist.

  4. Wähle Resolve Auto Layout Issues » All Views » Reset to Suggested Constraints um testweise automatisch Layout-Constraints für das View zu erstellen:

    Interface Builder: Reset to suggested constraints
  5. Prüfe die angelegten Constraints.

  6. Blende mit View as: ... die Größenauswahl für das Storyboard ein und prüfe das automatisch erstellte Layout für verschiedene iPhone-Größen und Rotationen:

    Xcode Storyboard Preview
  7. Wähle Resolve Auto Layout Issues » All Views » Clear Constraints um die Constraints wieder zu entfernen - die Constraints für das View werden im Folgenden manuell erstellt:

    Resolve Auto Layout Issues » All Views » Clear Constraints

Tutorial 3: Views mit Layout Constraints positionieren

  1. Ziehe schräg vom Textfeld auf das umgebende View und erstelle einen Equal Height Constraint, um die Größe des Textfeldes abhängig von dem zur Verfügung stehenden Platz zu machen:

    Equal Height Constraint für Textfeld erstellen

    Der erstellte Constraint wird rot dargestellt, weil die Constraints für das Textfeld noch keine vollständige Positionierung ergeben.

  2. Wähle den Equal Height-Constraint aus.
    Prüfe die Reihenfolge der Views im Constraint: First Item sollte das Text Label sein und Second Item das Superview. Wähle andernfalls im Auswahlmenü Reverse First and Second Item.
    Gebe als Constant 0 und als Multiplier 1:3 an, um dem Textfeld ein Drittel der Höhe des Controller-Views zuzuweisen:

    Equal Height Constraint bearbeiten

    Damit muss die Höhe des Text-Labels immer ein Drittel der Höhe des beinhaltenden Views sein:

    Text Label.Height = ⅓ * Superview.Height + 0

  3. Verwende Add New Constraints um das Textfeld auf eine feste Breite von 275 Punkt zu konfigurieren und erstelle mit Align zwei neue Constraints Horizontally + Vertically in Container für das Textfeld:

    Add New Constraints
    Horizontally + Vertically in Container
  4. Wähle den Center Y Constraint aus. Prüfe auch hier die Reihenfolge der Constraint-Items und konfiguriere einen Multiplier von 3:4 um das Textfeld anteilig oberhalb im Hintergrund-View zu platzieren:

    Center Y Constraint bearbeiten
  5. Wähle den Flip-Button aus und erstelle mittels Align einen Center Horizontally in Container-Constraint:

    Center Horizontally in Container
  6. Wähle die drei Buttons aus und verwende Align um ein Vertical Centers Constraint zu erstellen:

  7. Verwende Add Constraints um Abstände von 20 Punkt nach links und rechts und 60 Punkt nach unten zu erstellen:

  8. Prüfe die Constraints für verschiedene Bildschirmgrößen mit der Vorschau im Assistant Editor:

    Vorschau für verschiedene Bildschirmgrößen
  9. Starte die App im Simulator und drehe den Simulator mittels Hardware » Rotate Left/Right ⌘◀/▶