Layouts in Ansichten

Compose-Methode verwenden
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zum Arbeiten mit Layouts in Compose

Ein Layout definiert die Struktur für eine Benutzeroberfläche in Ihrer App, z. B. in einer Aktivität. Alle Elemente im Layout werden mit einer Hierarchie von View und ViewGroup Objekten erstellt. Ein View-Objekt zeichnet in der Regel etwas, das der Nutzer sehen und mit dem er interagieren kann. Ein ViewGroup ist ein unsichtbarer Container, der die Layoutstruktur für View und andere ViewGroup Objekte definiert, wie in Abbildung 1 dargestellt.

Abbildung 1 Abbildung einer Ansichtshierarchie, die ein UI-Layout definiert.

View-Objekte werden oft als Widgets bezeichnet und können eine von vielen Unterklassen sein, z. B. Button oder TextView. Die ViewGroup Objekte werden in der Regel als Layouts bezeichnet und können einer von vielen Typen sein, die eine andere Layoutstruktur bieten, z. B. LinearLayout oder ConstraintLayout.

Sie können ein Layout auf zwei Arten deklarieren:

  • UI-Elemente in XML deklarieren Android bietet ein einfaches XML Vokabular, das den View Klassen und Unterklassen entspricht, z. B. für Widgets und Layouts. Sie können auch den Layout-Editor von Android Studio verwenden, um Ihr XML- Layout mit einer Drag-and-drop-Oberfläche zu erstellen.

  • Layout-Elemente zur Laufzeit instanziieren Ihre App kann View und ViewGroup Objekte erstellen und ihre Eigenschaften programmatisch bearbeiten.

Wenn Sie Ihre UI in XML deklarieren, können Sie die Darstellung Ihrer App vom Code trennen, der ihr Verhalten steuert. Außerdem lassen sich mit XML-Dateien leichter verschiedene Layouts für unterschiedliche Bildschirmgrößen und Ausrichtungen bereitstellen. Weitere Informationen finden Sie unter Verschiedene Bildschirmgrößen unterstützen.

Das Android-Framework bietet Ihnen die Flexibilität, eine oder beide dieser Methoden zu verwenden, um die UI Ihrer App zu erstellen. Sie können beispielsweise die Standardlayouts Ihrer App in XML deklarieren und das Layout dann zur Laufzeit ändern.

XML schreiben

Mit dem XML-Vokabular von Android können Sie schnell UI-Layouts und die darin enthaltenen Bildschirmelemente entwerfen, so wie Sie Webseiten in HTML mit einer Reihe verschachtelter Elemente erstellen.

Jede Layoutdatei muss genau ein Stammelement enthalten, das ein View oder ViewGroup Objekt sein muss. Nachdem Sie das Stammelement definiert haben, können Sie weitere Layoutobjekte oder Widgets als untergeordnete Elemente hinzufügen, um schrittweise eine View-Hierarchie zu erstellen, die Ihr Layout definiert. Hier ist beispielsweise ein XML-Layout, das ein vertikales LinearLayout verwendet, um ein TextView- und ein Button-Objekt zu enthalten:

<?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:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" />
    <Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" />
</LinearLayout>

Nachdem Sie Ihr Layout in XML deklariert haben, speichern Sie die Datei mit der Erweiterung .xml im Verzeichnis res/layout/ Ihres Android-Projekts, damit sie ordnungsgemäß kompiliert wird.

Weitere Informationen zur Syntax für eine XML-Layoutdatei finden Sie unter Layout-Ressource.

XML-Ressource laden

Wenn Sie Ihre App kompilieren, wird jede XML-Layoutdatei in eine View-Ressource kompiliert. Laden Sie die Layout-Ressource in der Activity.onCreate()-Callback-Implementierung Ihrer App. Rufen Sie dazu setContentView(), auf und übergeben Sie die Referenz auf Ihre Layout-Ressource im folgenden Format: R.layout.layout_file_name. Wenn Ihr XML-Layout beispielsweise als main_layout.xml gespeichert ist, laden Sie es für Ihre Activity so:

Kotlin

fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_layout)
}

Java

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

Das Android-Framework ruft die onCreate()-Callback-Methode in Ihrer Activity auf, wenn die Activity gestartet wird. Weitere Informationen zu Aktivitätslebenszyklen finden Sie unter Einführung in Aktivitäten.

Attribute

Jedes View und ViewGroup Objekt unterstützt eine eigene Auswahl an XML-Attributen. Einige Attribute sind spezifisch für ein View-Objekt. TextView unterstützt beispielsweise das Attribut textSize. Diese Attribute werden jedoch auch von allen View-Objekten übernommen, die diese Klasse erweitern. Einige sind für alle View-Objekte gleich, da sie von der Stammklasse View übernommen werden, z. B. das Attribut id. Andere Attribute werden als Layoutparameter betrachtet. Das sind Attribute, die bestimmte Layoutausrichtungen des View Objekts beschreiben, wie sie vom übergeordneten ViewGroup Objekt dieses Objekts definiert werden.

ID

Jedem View-Objekt kann eine Ganzzahl-ID zugewiesen werden, um das View-Objekt im Baum eindeutig zu identifizieren. Wenn die App kompiliert wird, wird auf diese ID als Ganzzahl verwiesen. Die ID wird jedoch in der Regel in der XML-Layoutdatei als String im Attribut id zugewiesen. Dies ist ein XML-Attribut, das für alle View-Objekte gleich ist und von der Klasse View definiert wird. Es wird sehr häufig verwendet. Die Syntax für eine ID in einem XML-Tag sieht so aus:

android:id="@+id/my_button"

Das At-Symbol (@) am Anfang des Strings gibt an, dass der XML-Parser den Rest des ID-Strings parst und erweitert und ihn als ID-Ressource identifiziert. Das Pluszeichen (+) bedeutet, dass dies ein neuer Ressourcenname ist, der erstellt und in der Datei R.java zu Ihren Ressourcen hinzugefügt werden muss.

Das Android-Framework bietet viele weitere ID-Ressourcen. Wenn Sie auf eine Android-Ressourcen-ID verweisen, benötigen Sie das Pluszeichen nicht, müssen aber den Paket-Namespace android so hinzufügen:

android:id="@android:id/empty"

Der Paket-Namespace android gibt an, dass Sie auf eine ID aus der Ressourcenklasse android.R und nicht auf die lokale Ressourcenklasse verweisen.

So erstellen Sie Ansichten und verweisen von Ihrer App darauf:

  1. Definieren Sie eine Ansicht in der Layoutdatei und weisen Sie ihr eine eindeutige ID zu, wie im folgenden Beispiel:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
  2. Erstellen Sie eine Instanz des Ansichtsobjekts und erfassen Sie sie aus dem Layout, in der Regel in der onCreate() Methode, wie im folgenden Beispiel gezeigt:

    Kotlin

    val myButton: Button = findViewById(R.id.my_button)

    Java

    Button myButton = (Button) findViewById(R.id.my_button);

Das Definieren von IDs für Ansichtsobjekte ist wichtig, wenn Sie ein RelativeLayout erstellen. In einem relativen Layout können gleichgeordnete Ansichten ihr Layout relativ zu einer anderen gleichgeordneten Ansicht definieren, auf die mit der eindeutigen ID verwiesen wird.

Eine ID muss nicht im gesamten Baum eindeutig sein, aber sie muss im Teil des Baums eindeutig sein, den Sie durchsuchen. Oft ist es der gesamte Baum. Daher ist es am besten, sie nach Möglichkeit eindeutig zu machen.

Layoutparameter

XML-Layoutattribute mit dem Namen layout_something definieren Layoutparameter für das View-Objekt, die für das ViewGroup-Objekt geeignet sind, in dem es sich befindet.

Jede ViewGroup Klasse implementiert eine verschachtelte Klasse, die erweitertViewGroup.LayoutParams. Diese Unterklasse enthält Eigenschaftstypen, die die Größe und Position jeder untergeordneten Ansicht definieren, je nach Ansichtsgruppe. Wie in Abbildung 2 dargestellt, definiert die übergeordnete Ansichtsgruppe Layoutparameter für jede untergeordnete Ansicht, einschließlich der untergeordneten Ansichtsgruppe.

Abbildung 2. Visualisierung einer Ansichtshierarchie mit Layout parametern, die jeder Ansicht zugeordnet sind.

Jede LayoutParams-Unterklasse hat eine eigene Syntax zum Festlegen von Werten. Jedes untergeordnete Element muss ein LayoutParams-Objekt definieren, das für das übergeordnete Element geeignet ist. Es kann aber auch ein anderes LayoutParams-Objekt für seine eigenen untergeordneten Elemente definieren.

Alle Ansichtsgruppen haben eine Breite und Höhe, die mit layout_width und layout_height festgelegt werden. Jede Ansicht muss diese definieren. Viele LayoutParams-Objekte enthalten optionale Ränder und Rahmen.

Sie können Breite und Höhe mit genauen Maßen angeben, aber das ist in der Regel nicht empfehlenswert. Meistens verwenden Sie eine der folgenden Konstanten, um die Breite oder Höhe festzulegen:

  • wrap_content: Die Ansicht wird so groß wie nötig, um ihren Inhalt aufzunehmen.
  • match_parent: Die Ansicht wird so groß wie die übergeordnete Ansichtsgruppe.

Im Allgemeinen empfehlen wir, Breite und Höhe eines Layouts nicht mit absoluten Einheiten wie Pixeln anzugeben. Besser sind relative Maße wie dichteunabhängige Pixeleinheiten (dp), wrap_content oder match_parent, da Ihre App so auf einer Vielzahl von Geräten mit unterschiedlichen Bildschirmgrößen richtig angezeigt wird. Die akzeptierten Maßeinheiten sind unter Layout-Ressource definiert.

Layout position

Eine Ansicht hat eine rechteckige Geometrie. Sie hat eine Position, ausgedrückt als Paar von linken und oberen Koordinaten, und zwei Dimensionen, ausgedrückt als Breite und Höhe. Die Einheit für Position und Dimensionen ist das Pixel.

Sie können die Position einer Ansicht abrufen, indem Sie die Methoden getLeft() und getTop() aufrufen. Die erste Methode gibt die linke (x)-Koordinate des Rechtecks zurück, das die Ansicht darstellt. Die zweite Methode gibt die obere (y)-Koordinate des Rechtecks zurück, das die Ansicht darstellt. Diese Methoden geben die Position der Ansicht relativ zum übergeordneten Element zurück. Wenn getLeft() beispielsweise 20 zurückgibt, befindet sich die Ansicht 20 Pixel rechts vom linken Rand des direkten übergeordneten Elements.

Außerdem gibt es praktische Methoden, um unnötige Berechnungen zu vermeiden: getRight() und getBottom(). Diese Methoden geben die Koordinaten des rechten und unteren Rands des Rechtecks zurück, das die Ansicht darstellt. Der Aufruf von getRight() entspricht beispielsweise der folgenden Berechnung: getLeft() + getWidth().

Größe, Padding und Ränder

Die Größe einer Ansicht wird mit einer Breite und Höhe angegeben. Eine Ansicht hat zwei Paare von Breiten- und Höhenwerten.

Das erste Paar wird als gemessene Breite und gemessene Höhe bezeichnet. Diese Dimensionen definieren, wie groß eine Ansicht innerhalb des übergeordneten Elements sein soll. Sie können die gemessenen Dimensionen mit getMeasuredWidth() und getMeasuredHeight() abrufen.

Das zweite Paar wird als Breite und Höhe oder manchmal Zeichnungsbreite und Zeichnungshöhe bezeichnet. Diese Dimensionen definieren die tatsächliche Größe der Ansicht auf dem Bildschirm zur Zeichnungszeit und nach dem Layout. Diese Werte können sich von der gemessenen Breite und Höhe unterscheiden, müssen aber nicht. Sie können die Breite und Höhe mit getWidth() und getHeight() abrufen.

Bei der Messung der Dimensionen berücksichtigt eine Ansicht ihr Padding. Das Padding wird in Pixeln für die linke, obere, rechte und untere Seite der Ansicht angegeben. Mit Padding können Sie den Inhalt der Ansicht um eine bestimmte Anzahl von Pixeln versetzen. Ein linkes Padding von zwei verschiebt den Inhalt der Ansicht beispielsweise um zwei Pixel nach rechts vom linken Rand. Sie können das Padding mit der Methode setPadding(int, int, int, int) festlegen und mit getPaddingLeft(), getPaddingTop(), getPaddingRight() und getPaddingBottom() abfragen.

Eine Ansicht kann zwar ein Padding definieren, aber keine Ränder. Ansichtsgruppen unterstützen jedoch Ränder. Weitere Informationen finden Sie unter ViewGroup und ViewGroup.MarginLayoutParams.

Weitere Informationen zu Dimensionen finden Sie unter Dimension.

Neben dem programmatischen Festlegen von Rändern und Padding können Sie sie auch in Ihren XML-Layouts festlegen, wie im folgenden Beispiel gezeigt:

  <?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:id="@+id/text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="16dp"
                android:padding="8dp"
                android:text="Hello, I am a TextView" />
      <Button android:id="@+id/button"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="16dp"
              android:paddingBottom="4dp"
              android:paddingEnd="8dp"
              android:paddingStart="8dp"
              android:paddingTop="4dp"
              android:text="Hello, I am a Button" />
  </LinearLayout>
  

Im vorherigen Beispiel werden Ränder und Padding angewendet. Auf das TextView-Objekt werden einheitliche Ränder und einheitliches Padding angewendet. Das Button-Objekt zeigt, wie Sie sie unabhängig voneinander auf verschiedene Ränder anwenden können.

Häufig verwendete Layouts

Jede Unterklasse der Klasse ViewGroup bietet eine einzigartige Möglichkeit, die darin verschachtelten Ansichten anzuzeigen. Der flexibelste Layouttyp und derjenige, der die besten Tools bietet, um die Layout-Hierarchie flach zu halten, ist ConstraintLayout.

Im Folgenden sind einige der häufig verwendeten Layouttypen aufgeführt, die in die Android-Plattform integriert sind.

Ordnet die untergeordneten Elemente in einer einzelnen horizontalen oder vertikalen Zeile an und erstellt eine Bildlaufleiste, wenn die Länge des Fensters die Länge des Bildschirms überschreitet.

Web-Apps in WebView erstellen

Zeigt Webseiten an.

Dynamische Listen erstellen

Wenn der Inhalt für Ihr Layout dynamisch oder nicht vorab festgelegt ist, können Sie RecyclerView oder eine Unterklasse von AdapterView verwenden. RecyclerView ist in der Regel die bessere Option, da es den Arbeitsspeicher effizienter nutzt als AdapterView.

Häufig verwendete Layouts, die mit RecyclerView und AdapterView möglich sind, sind:

Liste

Zeigt eine Bildlaufliste mit einer Spalte an.

Raster

Zeigt ein Bildlaufraster mit Spalten und Zeilen an.

RecyclerView bietet mehr Möglichkeiten und die Option, einen benutzerdefinierten Layout-Manager zu erstellen.

Adapteransicht mit Daten füllen

Sie können ein AdapterView wie ListView oder GridView füllen, indem Sie die AdapterView Instanz an einen Adapter binden, der Daten aus einer externen Quelle abruft und ein View erstellt, das jeden Dateneintrag darstellt.

Android bietet mehrere Unterklassen von Adapter, die nützlich sind , um verschiedene Arten von Daten abzurufen und Ansichten für ein AdapterView zu erstellen. Die beiden häufigsten Adapter sind:

ArrayAdapter
Verwenden Sie diesen Adapter, wenn Ihre Datenquelle ein Array ist. Standardmäßig erstellt ArrayAdapter eine Ansicht für jedes Array-Element, indem toString() für jedes Element aufgerufen und der Inhalt in ein TextView eingefügt wird.

Wenn Sie beispielsweise ein Array von Strings haben, die in einem ListView angezeigt werden sollen, initialisieren Sie ein neues ArrayAdapter mit einem Konstruktor, um das Layout für jeden String und das String-Array anzugeben:

Kotlin

    val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)
    

Java

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, myStringArray);
    

Die Argumente für diesen Konstruktor sind:

  • Ihrer App Context
  • Das Layout, das ein TextView für jeden String im Array enthält
  • Das String-Array

Rufen Sie dann setAdapter() für Ihr ListView auf:

Kotlin

    val listView: ListView = findViewById(R.id.listview)
    listView.adapter = adapter
    

Java

    ListView listView = (ListView) findViewById(R.id.listview);
    listView.setAdapter(adapter);
    

Wenn Sie die Darstellung der einzelnen Elemente anpassen möchten, können Sie die toString() Methode für die Objekte in Ihrem Array überschreiben. Wenn Sie für jedes Element eine andere Ansicht als ein TextView erstellen möchten, z. B. ein ImageView für jedes Array-Element, erweitern Sie die Klasse ArrayAdapter und überschreiben Sie getView() , um den gewünschten Ansichtstyp für jedes Element zurückzugeben.

SimpleCursorAdapter
Verwenden Sie diesen Adapter, wenn Ihre Daten aus einem Cursor. Wenn Sie SimpleCursorAdapter verwenden, geben Sie ein Layout an, das für jede Zeile im Cursor verwendet werden soll, und welche Spalten im Cursor in die Ansichten des gewünschten Layouts eingefügt werden sollen. Wenn Sie beispielsweise eine Liste mit Namen und Telefon nummern von Personen erstellen möchten, können Sie eine Abfrage ausführen, die ein Cursor mit einer Zeile für jede Person und Spalten für die Namen und Nummern zurückgibt. Anschließend erstellen Sie ein String-Array, in dem Sie angeben, welche Spalten aus dem Cursor für jedes Ergebnis im Layout verwendet werden sollen, und ein Ganzzahl Array, in dem Sie die entsprechenden Ansichten angeben, in denen die einzelnen Spalten platziert werden sollen:

Kotlin

    val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME,
                              ContactsContract.CommonDataKinds.Phone.NUMBER)
    val toViews = intArrayOf(R.id.display_name, R.id.phone_number)
    

Java

    String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
                            ContactsContract.CommonDataKinds.Phone.NUMBER};
    int[] toViews = {R.id.display_name, R.id.phone_number};
    

Wenn Sie das SimpleCursorAdapter-Objekt instanziieren, übergeben Sie das Layout, das für jedes Ergebnis verwendet werden soll, das Cursor-Objekt mit den Ergebnissen und diese beiden Arrays:

Kotlin

    val adapter = SimpleCursorAdapter(this,
            R.layout.person_name_and_number, cursor, fromColumns, toViews, 0)
    val listView = getListView()
    listView.adapter = adapter
    

Java

    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
            R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
    ListView listView = getListView();
    listView.setAdapter(adapter);
    

Das SimpleCursorAdapter-Objekt erstellt dann für jede Zeile im Cursor-Objekt eine Ansicht mit dem angegebenen Layout, indem es jedes fromColumns-Element in die entsprechende toViews-Ansicht einfügt.

Wenn Sie im Laufe der Lebensdauer Ihrer App die zugrunde liegenden Daten ändern, die von Ihrem Adapter gelesen werden, rufen Sie notifyDataSetChanged() auf. Dadurch wird die angehängte Ansicht benachrichtigt, dass die Daten geändert wurden, und sie wird aktualisiert.

Click-Events verarbeiten

Sie können auf Click-Events für jedes Element in einem AdapterView reagieren, indem Sie die AdapterView.OnItemClickListener Schnittstelle implementieren. Beispiel:

Kotlin

listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
    // Do something in response to the click.
}

Java

// Create a message handling object as an anonymous class.
private OnItemClickListener messageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id) {
        // Do something in response to the click.
    }
};

listView.setOnItemClickListener(messageClickedHandler);

Zusätzliche Ressourcen

Informationen zur Verwendung von Layouts in der Sunflower Demo-App auf GitHub