Layouts in Ansichten
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. Mit einem View wird in der Regel etwas gezeichnet, das der Nutzer sehen und mit dem er interagieren kann. Ein ViewGroup ist ein unsichtbarer Container, der das Layout für View und andere ViewGroup-Objekte definiert (siehe Abbildung 1).
View-Objekte werden häufig als Widgets bezeichnet und können einer von vielen Unterklassen sein, z. B. Button oder TextView. Die ViewGroup-Objekte werden in der Regel als Layouts bezeichnet und können einen von vielen Typen haben, die eine unterschiedliche Layoutstruktur bieten, z. B. LinearLayout oder ConstraintLayout.
Sie haben zwei Möglichkeiten, ein Layout zu 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 über eine Drag-and-drop-Oberfläche zu erstellen. - Layout-Elemente zur Laufzeit instanziieren: Ihre App kann
View- undViewGroup-Objekte erstellen und ihre Eigenschaften programmatisch bearbeiten.
Wenn Sie die Benutzeroberfläche in XML deklarieren, können Sie die Darstellung Ihrer App vom Code trennen, der ihr Verhalten steuert. Außerdem können Sie 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 zum Erstellen der Benutzeroberfläche Ihrer App zu verwenden. 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. Das funktioniert ähnlich wie beim Erstellen von Webseiten in HTML mit einer Reihe von verschachtelten Elementen.
Jede Layoutdatei muss genau ein Stammelement enthalten, das ein View- oder ViewGroup-Objekt sein muss. Nachdem Sie das Stammelement definiert haben, können Sie zusätzliche Layoutobjekte oder Widgets als untergeordnete Elemente hinzufügen, um nach und nach eine View-Hierarchie zu erstellen, die Ihr Layout definiert. Hier ist ein Beispiel für ein XML-Layout, in dem ein vertikales LinearLayout verwendet wird, um ein TextView und ein Button 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 das Layout in XML deklariert haben, speichern Sie die Datei mit der Erweiterung .xml im Verzeichnis res/layout/ Ihres Android-Projekts, damit sie richtig kompiliert wird.
Weitere Informationen zur Syntax einer XML-Datei für das Layout 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 Layoutressource in der Callback-Implementierung Activity.onCreate() Ihrer App. Rufen Sie dazu setContentView() auf und übergeben Sie die Referenz zu Ihrer Layoutressource in der Form R.layout.layout_file_name. Wenn Ihr XML-Layout beispielsweise als main_layout.xml gespeichert ist, laden Sie es für Ihr 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 Callback-Methode onCreate() in Ihrem Activity auf, wenn das 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 geerbt werden, z. B. das Attribut id. Andere Attribute gelten als Layoutparameter. 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 im Baum eindeutig zu identifizieren. Wenn die App kompiliert wird, wird auf diese ID als Ganzzahl verwiesen. Die ID wird jedoch normalerweise in der XML-Layoutdatei als String im Attribut id zugewiesen. Dies ist ein XML-Attribut, das für alle View-Objekte gilt und von der Klasse View definiert wird. Sie verwenden es sehr oft. Die Syntax für eine ID in einem XML-Tag lautet so:
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 den Ressourcen in der Datei R.java 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 wie folgt 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 aus der lokalen Ressourcenklasse verweisen.
Wenn Sie Ansichten erstellen und in Ihrer App darauf verweisen möchten, können Sie ein gemeinsames Muster verwenden:
- 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"/>
- Erstellen Sie eine Instanz des Ansichtsobjekts und erfassen Sie sie aus dem Layout, in der Regel in der Methode
onCreate(), 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 untergeordnete Ansichten ihr Layout relativ zu einer anderen untergeordneten Ansicht definieren, auf die mit der eindeutigen ID verwiesen wird.
Eine ID muss nicht im gesamten Baum eindeutig sein, sondern nur in dem Teil des Baums, in dem Sie suchen. Häufig ist es der gesamte Baum. Daher ist es am besten, ihn nach Möglichkeit eindeutig zu gestalten.
Layoutparameter
XML-Layoutattribute mit dem Namen layout_something definieren Layoutparameter für das View, die für das ViewGroup geeignet sind, in dem es sich befindet.
Jede ViewGroup-Klasse implementiert eine verschachtelte Klasse, die ViewGroup.LayoutParams erweitert.
Diese Unterklasse enthält Attributtypen, die die Größe und Position jeder untergeordneten Ansicht definieren, je nach Ansichtsgruppe. Wie in Abbildung 2 dargestellt, werden in der übergeordneten Ansichtsgruppe Layoutparameter für jede untergeordnete Ansicht definiert, einschließlich der untergeordneten Ansichtsgruppe.
Jede LayoutParams-Unterklasse hat eine eigene Syntax zum Festlegen von Werten. In jedem untergeordneten Element muss ein LayoutParams definiert werden, das für das übergeordnete Element geeignet ist. Es kann aber auch ein anderes LayoutParams für seine eigenen untergeordneten Elemente definiert werden.
Alle Ansichtsgruppen haben eine Breite und Höhe, die mit layout_width und layout_height angegeben werden. Jede Ansicht muss diese definieren. Viele LayoutParams 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. Häufiger verwenden Sie eine dieser Konstanten, um die Breite oder Höhe festzulegen:
wrap_content: Die Ansicht wird an die Abmessungen angepasst, die für den Inhalt erforderlich sind.match_parent: Die Ansicht wird so groß wie möglich, basierend auf der übergeordneten Ansichtsgruppe.
Im Allgemeinen empfehlen wir, die Breite und Höhe eines Layouts nicht mit absoluten Einheiten wie Pixeln anzugeben. Eine bessere Methode ist die Verwendung relativer Maßeinheiten wie dichteunabhängiger Pixeleinheiten (dp), wrap_content oder match_parent, da Ihre App so auf einer Vielzahl von Gerätebildschirmgrößen richtig angezeigt wird. Die zulässigen Messarten sind in der Layout-Ressource definiert.
Layout position
Eine Ansicht hat eine rechteckige Geometrie. Es hat einen Standort, der als Paar von left- und top-Koordinaten ausgedrückt wird, und zwei Dimensionen, die als Breite und Höhe ausgedrückt werden. Die Einheit für Position und Abmessungen ist das Pixel.
Sie können den Standort einer Ansicht abrufen, indem Sie die Methoden getLeft() und getTop() aufrufen.
Ersteres gibt die linke (x) Koordinate des Rechtecks zurück, das die Ansicht darstellt. Letztere 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, bedeutet das, dass sich die Ansicht 20 Pixel rechts vom linken Rand des direkten übergeordneten Elements befindet.
Außerdem gibt es praktische Methoden, um unnötige Berechnungen zu vermeiden, nämlich getRight() und getBottom().
Diese Methoden geben die Koordinaten der rechten und unteren Kanten des Rechtecks zurück, das die Ansicht darstellt. Der Aufruf von getRight() entspricht beispielsweise der folgenden Berechnung: getLeft() + getWidth().
Größe, Innen- und Außenabstand
Die Größe einer Ansicht wird durch eine Breite und eine 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. Mit diesen Dimensionen wird festgelegt, wie groß eine Ansicht innerhalb des übergeordneten Elements sein soll. Sie können die gemessenen Dimensionen abrufen, indem Sie getMeasuredWidth() und getMeasuredHeight() aufrufen.
Das zweite Paar wird als Breite und Höhe oder manchmal als Zeichenbreite und Zeichenhöhe bezeichnet. Diese Dimensionen definieren die tatsächliche Größe der Ansicht auf dem Bildschirm zur Zeichenzeit und nach dem Layout. Diese Werte können, müssen aber nicht von der gemessenen Breite und Höhe abweichen. Sie können die Breite und Höhe durch Aufrufen von getWidth() und getHeight() abrufen.
Um die Abmessungen zu messen, wird das Padding einer Ansicht berücksichtigt. Der Abstand 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. Wenn Sie beispielsweise einen linken Abstand von 2 festlegen, wird der Inhalt der Ansicht um 2 Pixel nach rechts verschoben. Sie können das Padding mit der Methode setPadding(int, int, int, int) festlegen und es mit den Methoden getPaddingLeft(), getPaddingTop(), getPaddingRight() und getPaddingBottom() abfragen.
In einer Ansicht kann zwar ein Innenabstand definiert werden, 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 Innenabstand können Sie diese 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 sehen Sie, wie Rand und Innenabstand angewendet werden. Für TextView werden einheitliche Ränder und Innenabstände angewendet. Button zeigt, wie Sie sie unabhängig voneinander auf verschiedene Kanten anwenden können.
Häufig verwendete Layouts
Jede Unterklasse der ViewGroup-Klasse bietet eine einzigartige Möglichkeit, die darin verschachtelten Ansichten darzustellen. Der flexibelste Layouttyp, der die besten Tools bietet, um die Layout-Hierarchie flach zu halten, ist ConstraintLayout.
Im Folgenden sind einige der gängigen 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 Scrollleiste, wenn die Länge des Fensters die Länge des Bildschirms überschreitet.
Dynamische Listen erstellen
Wenn der Inhalt für Ihr Layout dynamisch oder nicht im Voraus festgelegt ist, können Sie RecyclerView oder eine Unterklasse von AdapterView verwenden.
RecyclerView ist in der Regel die bessere Option, da der Arbeitsspeicher effizienter genutzt wird als bei AdapterView.
Häufige Layouts, die mit RecyclerView und AdapterView möglich sind:
RecyclerView bietet mehr Möglichkeiten und die Option, einen benutzerdefinierten Layoutmanager zu erstellen.
Adapteransicht mit Daten füllen
Sie können ein AdapterView wie ListView oder GridView füllen, indem Sie die AdapterView-Instanz an ein Adapter binden. Dadurch werden Daten aus einer externen Quelle abgerufen und ein View erstellt, das jeden Dateneintrag darstellt.
Android bietet mehrere Unterklassen von Adapter, die zum Abrufen verschiedener Arten von Daten und zum Erstellen von Ansichten für ein AdapterView nützlich sind. Die beiden häufigsten Adapter sind:
ArrayAdapter- Verwenden Sie diesen Adapter, wenn Ihre Datenquelle ein Array ist. Standardmäßig wird mit
ArrayAdaptereine Ansicht für jedes Array-Element erstellt. Dazu wirdtoString()für jedes Element aufgerufen und der Inhalt in einTextVieweingefügt.Wenn Sie beispielsweise ein Array von Strings haben, das in einem
ListViewangezeigt werden soll, initialisieren Sie ein neuesArrayAdaptermit 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:
- Ihre App
Context - Das Layout, das ein
TextViewfür jeden String im Array enthält - Das String-Array
Rufen Sie dann
setAdapter()auf IhremListViewauf:Kotlin
val listView: ListView = findViewById(R.id.listview) listView.adapter = adapter
Java
ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(adapter);
Wenn Sie das Aussehen der einzelnen Elemente anpassen möchten, können Sie die Methode
toString()für die Objekte in Ihrem Array überschreiben. Wenn Sie eine Ansicht für jedes Element erstellen möchten, das keinTextViewist, z. B. wenn Sie einImageViewfür jedes Array-Element wünschen, erweitern Sie die KlasseArrayAdapterund überschreiben SiegetView(), um den gewünschten Ansichtstyp für jedes Element zurückzugeben. - Ihre App
SimpleCursorAdapter- Verwenden Sie diesen Adapter, wenn Ihre Daten aus einer
Cursorstammen. Wenn SieSimpleCursorAdapterverwenden, geben Sie ein Layout für jede Zeile inCursoran und legen Sie fest, welche Spalten inCursorin die Ansichten des gewünschten Layouts eingefügt werden sollen. Wenn Sie beispielsweise eine Liste mit Namen und Telefonnummern von Personen erstellen möchten, können Sie eine Abfrage ausführen, die einCursorzurückgibt, das eine Zeile für jede Person und Spalten für die Namen und Nummern enthält. Anschließend erstellen Sie ein String-Array, in dem Sie für jedes Ergebnis die Spalten ausCursorangeben, die im Layout enthalten sein sollen, sowie ein Integer-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 die
SimpleCursorAdapterinstanziieren, übergeben Sie das Layout, das für jedes Ergebnis verwendet werden soll, dieCursormit 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);
Mit
SimpleCursorAdapterwird dann für jede Zeile inCursoreine Ansicht mit dem bereitgestellten Layout erstellt, indem jedesfromColumns-Element in die entsprechendetoViews-Ansicht eingefügt wird.
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 verknüpfte Ansicht benachrichtigt, dass sich die Daten geändert haben, 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
Hier finden Sie die Sunflower-Demo-App auf GitHub.


