Stand: 18.05.2018

3.1 Einführung

In diesem Kapitel geht es ausschließlich um das Visuelle, also die grafische Benutzerschnittstelle. Wie legt man die Anordnung, also das Layout der verschiedenen Komponenten (Textfelder, Buttons, Slider etc.) fest?

Was bei allen grafischen Oberflächen aber die große Herausforderung ist: Wie gehe ich mit der Tatsache um, dass es verschieden große Screens gibt und dass die Screen entweder horizontal (Landscape) oder vertikal (Portrait) orientiert sein kann?

3.1.1 Objekte

In objektorientierten Programmiersprachen sind sichtbare grafische Komponenten wie Buttons und Textfelder Objekte, also Instanzen von Klassen. Das ist aus Sicht des Programmierers intuitiv und aus Sicht der Softwaretechnik gutes Design.

Klassen und Objekte im Layout

Wichtig ist, dass es auch nicht-sichtbare Objekte gibt, die eine reine Layout-Funktion haben. Diese Objekte dienen als Container, die andere Objekte (z.B. Textfelder und Buttons) enthalten und bestimmen, wo diese enthaltenen Objekte darzustellen sind.

Ein Beispiel ist ein Layout-Objekt vom Typ LinearLayout, welches verschiedenen sichtbare Komponenten enthalten kann und diese einfach entlang einer Linie anordnet. Hier z.B. einmal vertikal, einmal horizontal:

LinearLayout

Diese Layout-Objekte können sowohl sichtbare als auch nicht-sichtbare Komponenten enthalten.

3.1.2 Baumstruktur

Alle sichtbaren Objekte (z.B. Textfelder, Buttons) sind Instanzen von Unterklassen der Klasse View. Solche Komponenten werden auch Widgets genannt.

Alle nicht-sichtbaren (Layout-) Objekte sind Instanzen von Unterklasen der Klase ViewGroup. Da ein Layout-Objekt auch weitere Layout-Objekte beinhalten kann, können wir komplexe Layouts durch Verschachtelung herstellen.

Hier sieht man einfach ein vertikales LinearLayout (lila) und, darin enthalten, ein horizontales LinearLayout (gelb).

Layout

Ein Layout besteht also aus einer Verschachtelung von Views und ViewGroups. Zusammen ergibt sich eine Baumstruktur:

Layout

Google empfiehlt aus Performance-Gründen, die Verschachtelungstiefe möglichst klein zu halten.

Eine

An der Spitze des dargestellten Baums steht immer eine ViewGroup. Man nennt diese auch das Wurzel-Layout (engl. root layout).

Zwei sehr häufige Layouts sind LinearLayout und RelativeLayout. Seit neuestem wird ein weiteres Layout als das Layout verwendet: das ConstraintLayout.

3.1.3 Grafischer Editor

Das Layout wird mit Hilfe einer XML-Datei spezifiziert. Android Studio bietet parallel dazu einen grafischen Editor an. Man kann dann bequem von der XML-Datei auf den Editor umschalten und umgekehrt.

Um das Layout zu bearbeiten, geht man auf das Layout-XML, z.B. res/layout/activity_main.xml. Normalerweise sieht man zunächst den grafischen Editor:

UI-Editor

Links unten sieht man zwei "Reiter" (Tabs) mit den Bezeichnern Design und Text. Dort können Sie zwischen der XML-Sicht (Text) und der grafischen Sicht (Design) umschalten.

Sie sollten auf jeden Fall mit beiden Sichten vertraut sein. Viele Dinge kann man schneller und übersichtlicher in der Text-Sicht lösen. Dort kann man auch schnell Komponenten aus anderen Projekten mit einem einfachen Copy-n-Paste kopieren.

3.2 LinearLayout

LinearLayout packt alle Komponenten in eine horizontale oder vertikale Reihe.

LinearLayout

Um LinearLayout auszuprobieren, erstellen Sie ein neues Projekt und gehen in die Textansicht von activity_main.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="de.michaelkipp.linearlayoutsimple.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Jetzt ersetzen Sie ConstraintLayout durch LinearLayout. Löschen Sie am besten mit der BACKSPACE-Taste, dann wird der Text sowohl im öffnenden als auch im schließenden Tag ersetzt. Sie ersetzen

android.support.constraint.ConstraintLayout

durch

LinearLayout

D.h. Sie benötigen für LinearLayout keinen "Pfad".

Fügen Sie jetzt noch die Eigenschaft "orientation" mit dem Wert "vertical" hinzu.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:orientation="vertical">

Außerdem können Sie noch alle Angaben, in denen "tools" vorkommt, löschen. Achten Sie darauf, dass die spitzen Klammern erhalten bleiben:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

</LinearLayout>

3.2.1 Layouten mit Verschachtelung

Prinzipiell layouten Sie mit LinearLayout, indem Sie mehrere LinearLayout-Objekte verschachteln. Hier sehen Sie ein einfaches Beispiel mit zwei Layout-Objekten:

LinearLayout: Einfaches Beispiel

Sie können mit Hilfe von Verschachtelung erstaunlich komplexe Layouts anfertigen. Hier ein Beispiel:

LinearLayout: Komplexes Beispiel

Wenn Sie sich ein beliebiges Fenster anschauen, egal ob auf dem Handy oder auf dem Laptop, dann können Sie für die meisten Fenster eine Reihe von LinearLayout-Container einzeichnen und das Fenster i.d.R. auch in Android nachbauen.

3.2.2 Schritt-für-Schritt-Beispiel

Wie bekommt man ein verschachteltes Layout in Android Studio hin? Nehmen wir an, Sie haben Ihr ConstraintLayout bereits ersetzt durch ein LinearLayout, d.h. Ihre Layoutdatei sieht so aus:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</LinearLayout>

Jetzt können Sie in der Design-Ansicht weitere Layout-Container hinzufügen. Das tun Sie am besten im Component Tree-Fenster links unten von der Vorschau:

LinearLayout: Schritt 1

Wählen Sie im Palettenfenster den Reiter "Layout" und ziehen Sie zwei Mal ein LinearLayout (horizontal) in den Component Tree in das bestehende LinearLayout hinein. Das müsste dann so aussehen:

LinearLayout: Schritt 2

Damit wir in der Vorschau auch was sehen, müssen wir sichtbare Komponenten ins Design ziehen. Auch hier arbeiten wir im Component Tree. Wählen Sie in der Palette den Reiter "Widgets" und ziehen Sie drei Buttons in das obere horizontale LinearLayout und dann zwei Buttons in das untere horizontale LinearLayout.

LinearLayout: Schritt 3

Sie sehen nur die obere Reihe Buttons! Warum? Das obere LinearLayout hat als Grundeinstellung layout_height:match_parent, d.h. der Container versucht, die ganze Screen zu beanspruchen und verdrängt das untere LinearLayout.

Die Lösung ist, bei beiden (horizontalen) LinearLayouts die layout_height auf wrap_content zu stellen:

LinearLayout: Schritt 4

Sie sehen, dass zwar viele Layouts möglich sind, dass Sie aber evtl. viel Zeit damit zubringen, die richtigen Feineinstellungen zu finden. Das hilft - wie immer - nur viel Praxis!

3.2.3 Einstellmöglichkeiten

Orientierung

Was bedeutet das alles? Die orientation bestimmt, ob die enthaltenen Elemente horizontal oder vertikal angeordnet werden.

Also so...

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:orientation="vertical">

... oder so:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:orientation="horizontal">

Layoutbreite und Layouthöhe

Bei layout_width und layout_height gibt es zwei Möglichkeiten:

Ersetzen Sie den TextView durch zwei Buttons:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Button 1" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Ein weiterer Button" />

</LinearLayout>

Sie sehen, dass beim ersten Button "match_parent" und beim zweiten Button "wrap_content" eingestellt ist:

LinearLayout

Ausrichtung

Über die Eigenschaft gravity können Sie die Ausrichtung der enthaltenen Komponenten einstellen:

<LinearLayout
    ...
    android:gravity="center"
    android:orientation="vertical">

Entsprechend sehen Sie:

LinearLayout

Sie können mit gravity alle Komponenten oben, unten, links, rechts oder eben zentriert ausrichten.

Gewichtung

Bei den Widgets können Sie die Gewichtung der Komponenten über layout_weight einstellen. Diese Werte sind relativ zu einander. In diesem Beispiel bekommt der erste Button Gewicht 2, der zweite Gewicht 1, d.h. der erste bekommt 2 von insgesamt 3 Anteilen Platz (also 2/3 des Raums), der zweite entsprechend nur 1/3.

<Button
    ...
    android:layout_weight="2"
    android:text="Button 1" />

<Button
    ...
    android:layout_weight="1"
    android:text="Ein weiterer Button" />

LinearLayout

Zwei weitere enorm wichtige Eigenschaften von sichtbaren Komponenten sind Margin und Padding.

Margin und Padding

Die Margin bestimmt den Außenabstand, d.h. den Abstand vom Rand der Komponente bis zum Rand des umgebenden Containers:

<Button
    ...
    android:layout_margin="20dp"
    ... />

LinearLayout

Man kann das auch für bestimmte Seiten spezifizieren:

<Button
    ...
    android:layout_marginBottom="20dp"
    android:layout_marginLeft="20dp"
    ... />

Das Padding ("Füllung") bestimmt den Innenabstand, d.h. den Abstand vom Rand der Komponente zum Inhalt (Text, Bild) hin. Hier für den unteren Button:

<Button
    ...
    android:padding="30dp"
    android:text="Ein weiterer Button" />

LinearLayout

Text

Natürlich können Sie bei Widgets wie Buttons oder Textfeldern auch den Text einstellen. Hier können Sie einfach im XML die Eigenschaft text ändern:

<Button
   ...
   android:text="Abschicken" />

3.3 RelativeLayout

Beim LinearLayout geht es darum, wie die enthaltenen Komponenten innerhalb des Containers angeordnet werden. Ein komplexes Layout erreicht man durch Verschachtelung.

Beim RelativeLayout versucht man, die enthaltenen Komponenten durch Beziehungen (engl. relations) soweit zu spezifizieren, dass Android sie sinnvoll positionieren kann. Da solche Beziehungen die mögliche Position einer Komponente einschränkt (engl. to constrain), kann man eine solche Beziehung auch Constraint nennen.

Im einem RelativeLayout-Objekt kann man einerseits zwei enthaltene Komponenten A und B zueinander in Beziehung setzen, z.B.

Andererseits kann man eine enthaltene Komponente A zu dem RelativeLayout-Objekt R selbst (also dem Container von A) in Beziehung setzen, z.B.

Um die Beziehungen/Constraints zu definieren, ist der jeweilige ID einer Komponente (Button, TextView etc.) wichtig. Diesen finden Sie im XML in der Form "@+id/". Wenn Sie keinen sehen, müssen Sie selbst diese Eigenschaft hinzufügen.

<Button
    android:id="@+id/button3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:text="Button" />

Im folgenden sehen wir uns die möglichen Beziehungen mit Beispielen an. Eine Tabelle mit allen Constraints finden Sie bei Tutorialspoint.

3.3.1 RelativeLayout erstellen

Wenn Sie ein frisches Projekt mit einem ConstraintLayout haben, dann müssen Sie das Layout-File dahingehend ändern, dass Sie sehen:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ...>

    ...

</RelativeLayout>

Sie dürfen die folgenden Beziehungen natürlich nur auf Komponenten anwenden, die sich innerhalb dieser Klammern befinden.

Natürlich dürfen Sie auch RelativeLayout und LinearLayout ineinander verschachteln. Die Beziehungen müssen aber eben in einem RelativeLayout-Container sein.

3.3.2 Beziehungen zwischen enthaltenen Komponenten

Wir beschäftigen uns zunächst mit den Beziehungen zwischen zwei enthaltenen Komponenten A und B. Diese Komponenten können beliebige Views sein, also z.B. Buttons, Bilder oder Textfelder.

Man kann zur Alignierung der Kanten folgende Constraints definieren. Die eigentlichen Eigenschaften heißen z.B. android:layout_alignTop. Hier ein Beispiel:

<Button
    android:id="@+id/button1"
    ... />

<Button
    android:id="@+id/button2"
    ...
    android:layout_alignStart="@+id/button1"/>

In den folgenden Grafiken sind der Übersichtlichkeit halber nur Kurzformen der Eigenschaftsbezeichner zu sehen. Statt "alignStart" heißt es also eigentlich "android:layout_alignStart".

Sie können zwei Komponenten also anhand einer Kante ausrichten/alignieren:

RelativeLayout: zwischen Komponenten

Man kann spezifizieren auf welcher Seite eine Nachbarkomponente steht. Den Abstand kann man dann mit Margin setzen.

RelativeLayout: zwischen Komponenten

Beispiel

Wir schauen uns ein Beispiel mit drei Textkomponenten an.

Wenn Sie eine Komponente ohne Beziehungen einsetzen, werden diese einfach links oben im jeweiligen Layout-Objekt positioniert.

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Es war einmal"
    android:textSize="30sp" />

RelativeLayout: Beispiel Texte

Jetzt können Sie mit Hilfe des Außenabstands die Komponente leicht verschieben:

<TextView
    ...
    android:layout_marginLeft="15dp"
    android:layout_marginTop="15dp"
    ... />

RelativeLayout: Beispiel Texte

Jetzt fügen wir zwei weitere Textfelder hinzu.

Diese sollen untereinander (below) und linksbündig (alignStart) positioniert sein. Wir definieren also die zwei Texte relativ zum ersten bzw. zum zweiten:

<TextView
    android:id="@+id/textView"
    ...
    android:layout_marginLeft="15dp"
    android:layout_marginTop="15dp"
    android:text="Es war einmal" />

<TextView
    android:id="@+id/textView2"
    ...
    android:layout_alignStart="@+id/textView"
    android:layout_below="@+id/textView"
    android:text="in einer Galaxy" />

<TextView
    android:id="@+id/textView3"
    ...
    android:layout_alignStart="@+id/textView2"
    android:layout_below="@+id/textView2"
    android:text="weit, weit entfernt" />

RelativeLayout: Beispiel Texte

Beachten Sie die Bedeutung der IDs im Code, um die Beziehungen definieren zu können.

3.3.3 Beziehungen zur Elternkomponente

Für eine Komponente K ist die Elternkomponente die Komponente "oben drüber", also der Container, der K enthält. Das ist in diesem Fall unser RelativeLayout-Objekt R.

Wir können K an den Rand der Elternkomponente R stellen:

RelativeLayout: Beziehungen zur Elternkomponente

Wir können auch innerhalb von R zentrieren:

RelativeLayout: Beziehungen zur Elternkomponente

Beispiel

Will man z.B. einen Button an den unteren Rand der Screen setzen wollen...

RelativeLayout: Button unten

...würde man schreiben

<Button
    ...
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="50dp"
    ... />

Die Schritte, um obiges Layout zu erreichen, sind also:

  1. setze den Button an den unteren Rand (alignParentBottom)
  2. zentriere ihn in der Horizontalen (centerHorizontal)
  3. lege einen festen Abstand zum unteren Rand fest (marginBottom)

Natürlich können Sie auch innerhalb eines RelativeLayout ein LinearLayout verwenden und umgekehrt.

3.4 Übungen

(A) LinearLayout

Realisieren Sie folgendes Layout und beachten Sie auch die Hinweise unten. Verwenden Sie dabei folgende Bestandteile (teils mehrfach):

LinearLayout-Übung

In der Landscape-Orientierung soll das ganze dann so aussehen:

LinearLayout-Übung in Landscape

Hinweise

(B) RelativeLayout

Verwenden Sie RelativeLayout, ein Textfeld und zwei Buttons, um folgendes Layout zu realisieren:

RelativeLayout-Übung

In der Landscape-Orientierung soll das ganze dann so aussehen:

RelativeLayout-Übung in Landscape