Benutzerdefinierte Ansichtskomponenten erstellen

Schreiben Sie jetzt
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Hier erfahren Sie, wie Sie in „Compose“ mit Layouts arbeiten.

Android bietet ein ausgereiftes und leistungsstarkes, komponentenbasiertes Modell zum Erstellen Ihrer Benutzeroberfläche, das auf grundlegende Layout-Klassen View und ViewGroup. Die Plattform umfasst ein verschiedene vorgefertigte View- und ViewGroup-Unterklassen – Widgets und Layouts, mit denen Sie Ihre Benutzeroberfläche erstellen können.

Eine unvollständige Liste der verfügbaren Widgets enthält Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner und je mehr für spezielle Zwecke AutoCompleteTextView, ImageSwitcher und TextSwitcher

Zu den verfügbaren Layouts gehören LinearLayout, FrameLayout, RelativeLayout, und andere. Weitere Beispiele finden Sie unter Gängige Layouts:

Wenn keines der vordefinierten Widgets oder Layouts Ihren Anforderungen entspricht, können Sie ein eigenes erstellen. View abgeleitete Klasse. Wenn Sie nur kleine Anpassungen an einem vorhandenen Widget vornehmen oder Layout können Sie vom Widget oder Layout abgeleitete Klassen erstellen und die zugehörigen Methoden überschreiben.

Wenn Sie Ihre eigenen View-Unterklassen erstellen, können Sie das Erscheinungsbild eines Bildschirmelements. Damit Sie eine Vorstellung davon haben, wie viel Kontrolle Sie mit benutzerdefinierten Ansichten erhalten, finden Sie hier einige Beispiele dafür, was Sie damit tun können:

  • Sie können einen vollständig benutzerdefiniert gerenderten View-Typ erstellen, zum Beispiel ein „Volume“ Steuerung“ Regler, der in 2D-Grafik gerendert wird und einer analogen elektronischen Steuerung ähnelt.
  • Sie können eine Gruppe von View-Komponenten zu einer neuen Komponente kombinieren, z. B. ein Kombinationsfeld (Kombination aus Pop-up-Liste und Textfeld für kostenlose Eingabe), ein Dual-Pane-Auswahlsteuerung (links und rechts mit einer Liste, die Sie neu zuweisen können) welches Element sich in welcher Liste befindet usw.
  • Sie können die Darstellung einer EditText-Komponente auf dem Bildschirm überschreiben. Die <ph type="x-smartling-placeholder"></ph> Die Beispiel-App NotePad nutzt dies, um eine mit Linien versehene Notepad-Seite zu erstellen.
  • Sie können andere Ereignisse wie Tastendrücke erfassen und individuell verarbeiten, z. B. wie bei einem Spiel.

In den folgenden Abschnitten wird erläutert, wie Sie benutzerdefinierte Ansichten erstellen und in Ihrer Anwendung verwenden. Für ausführliche Referenzinformationen finden Sie in der Klasse View.

Der grundlegende Ansatz

Hier finden Sie eine allgemeine Übersicht darüber, was Sie wissen müssen, um Ihr eigenes View zu erstellen. Komponenten:

  1. Erweitern Sie eine vorhandene View-Klasse oder eine abgeleitete Klasse um Ihre eigene Klasse.
  2. Überschreiben Sie einige der Methoden der übergeordneten Klasse. Die zu überschreibenden übergeordneten Klassenmethoden beginnen mit on, z. B. onDraw(), onMeasure(), und onKeyDown(). Dies ähnelt den on-Ereignissen in Activity oder ListActivity, die du -Überschreibung für Lebenszyklus- und andere Funktions-Hooks.
  3. Verwenden Sie die neue Erweiterungsklasse. Sobald Sie fertig sind, können Sie die neue Erweiterungsklasse anstelle von der Ansicht, auf der sie basiert.
<ph type="x-smartling-placeholder">

Vollständig angepasste Komponenten

Sie können vollständig benutzerdefinierte grafische Komponenten erstellen, Vielleicht möchten Sie ein grafisches VU-Messgerät, das wie eine alte analoge Anzeige aussieht, oder eine Textansicht zum Mitsingen. Eine hüpfende Kugel bewegt sich entlang der Worte, während Sie mit einer Karaokemaschine singen. Vielleicht möchtest du was die integrierten Komponenten gar nicht tun können, egal wie Sie sie kombinieren.

Glücklicherweise können Sie Komponenten erstellen, die so aussehen und funktionieren, wie Sie möchten, die Größe des Bildschirms und die verfügbare Prozessorleistung. muss möglicherweise auf einem Gerät ausgeführt werden, das wesentlich weniger Energie hat als der Desktop. .

Berücksichtigen Sie beim Erstellen einer vollständig benutzerdefinierten Komponente Folgendes:

  • Die allgemeinste Ansicht, die erweitert werden kann, ist View. Normalerweise beginnen Sie mit der Erweiterung um Ihre neue Super-Komponente zu erstellen.
  • Sie können einen Konstruktor angeben, der Attribute und Parameter aus der XML-Datei übernehmen kann, und Sie können eigene Attribute und Parameter, wie Farbe und Bereich des VU-Messtools oder die Breite und Dämpfung der Nadel.
  • Sie möchten Ihre eigenen Event-Listener, Property-Zugriffsfunktionen und Modifikatoren sowie in Ihrer Komponentenklasse.
  • Sie möchten mit hoher Wahrscheinlichkeit onMeasure() überschreiben und müssen überschreiben Sie onDraw(), wenn in der Komponente etwas angezeigt werden soll. Beide haben zwar hat die Standardeinstellung onDraw() keine Auswirkungen, die Standardeinstellung onMeasure() legt immer eine Größe von 100 × 100 fest, was Sie wahrscheinlich nicht möchten.
  • Bei Bedarf können Sie auch andere on-Methoden überschreiben.

onDraw() und onMeasure() erweitern

Die Methode onDraw() liefert ein Canvas, auf der Sie Implementieren Sie beliebig viele Elemente: 2D-Grafiken, andere Standard- oder benutzerdefinierte Komponenten, Text mit benutzerdefinierten Stilen oder was Ihnen sonst noch einfällt.

<ph type="x-smartling-placeholder">

onMeasure() ist ein bisschen komplizierter. onMeasure() ist ein wichtiger Bestandteil des Renderingvertrags zwischen der Komponente und ihrem Container. onMeasure() muss um die Messungen der darin enthaltenen Teile effizient und genau zu melden. Dies ist durch die Grenzwertanforderungen des übergeordneten Elements, die in die onMeasure() und der Anforderung zum Aufrufen der setMeasuredDimension()-Methode mit der gemessenen Breite und Höhe, sobald diese berechnet. Wenn Sie diese Methode nicht über eine überschriebene onMeasure()-Methode aufrufen, zu einer Ausnahme führen.

Im Großen und Ganzen sieht die Implementierung von onMeasure() in etwa so aus:

  • Die überschriebene onMeasure()-Methode wird mit Breite und Höhe aufgerufen. Spezifikationen, die als Anforderungen für die Breiten- und Höhenbeschränkungen gelten Ihre eigenen Messungen. widthMeasureSpec und heightMeasureSpec -Parameter sind beides Ganzzahlcodes, die Dimensionen darstellen. Ein vollständiger Verweis auf die Art von Einschränkungen für diese Spezifikationen finden Sie in der Referenzdokumentation unter View.onMeasure(int, int) In dieser Referenzdokumentation wird auch der gesamte Messvorgang erläutert.
  • Mit der onMeasure()-Methode Ihrer Komponente werden Breite und Höhe berechnet, die zum Rendern der Komponente erforderlich sind. Sie muss versuchen, die vorgegebenen Spezifikationen einzuhalten auch wenn sie diese übersteigen können. In diesem Fall können die Eltern entscheiden, was sie tun möchten: ausschneiden, scrollen, eine Ausnahme auslösen oder den onMeasure() bitten, es noch einmal zu versuchen. mit unterschiedlichen Messspezifikationen.
  • Wenn die Breite und Höhe berechnet werden, rufen Sie die Methode setMeasuredDimension(int width, int height)-Methode mit dem berechneten Messungen. Andernfalls wird eine Ausnahme ausgelöst.

Im Folgenden finden Sie eine Zusammenfassung weiterer Standardmethoden, die das Framework für Ansichten aufruft:

Kategorie Methoden Beschreibung
Erstellung Konstruktoren Es gibt eine Form des Konstruktors, die aufgerufen wird, wenn die Ansicht aus Code erstellt wird und ein Formular, das aufgerufen wird, wenn die Ansicht aufgrund einer Layoutdatei aufgebläht wird. Das zweite Formular parst und wendet die in der Layoutdatei definierten Attribute an.
onFinishInflate() Wird aufgerufen, nachdem eine Ansicht und alle ihre untergeordneten Elemente aus XML aufgebläht wurden.
Layout onMeasure(int, int) Wird aufgerufen, um die Größenanforderungen für diese Ansicht und alle ihrer untergeordneten Elemente.
onLayout(boolean, int, int, int, int) Wird aufgerufen, wenn diese Ansicht allen untergeordneten Elementen eine Größe und Position zuweisen muss.
onSizeChanged(int, int, int, int) Wird aufgerufen, wenn die Größe dieser Ansicht geändert wird.
Zeichnung onDraw(Canvas) Wird aufgerufen, wenn der Inhalt der Ansicht gerendert werden muss.
Ereignisverarbeitung onKeyDown(int, KeyEvent) Wird aufgerufen, wenn ein Key-Down-Ereignis auftritt.
onKeyUp(int, KeyEvent) Wird aufgerufen, wenn ein Schlüsselereignis eintritt.
onTrackballEvent(MotionEvent) Wird aufgerufen, wenn ein Trackball-Bewegungsereignis auftritt.
onTouchEvent(MotionEvent) Wird aufgerufen, wenn ein Touchscreen-Bewegungsereignis auftritt.
Fokus onFocusChanged(boolean, int, Rect) Wird aufgerufen, wenn der Aufruf zu- oder abnimmt.
onWindowFocusChanged(boolean) Wird aufgerufen, wenn das Fenster, das die Ansicht enthält, verstärkt oder hervorgehoben wird.
Wird angehängt onAttachedToWindow() Wird aufgerufen, wenn die Ansicht an ein Fenster angehängt wird.
onDetachedFromWindow() Wird aufgerufen, wenn die Ansicht vom Fenster getrennt wird.
onWindowVisibilityChanged(int) Wird aufgerufen, wenn die Sichtbarkeit des Fensters mit der Ansicht geändert wird.

Zusammengesetzte Steuerelemente

Wenn Sie keine vollständig benutzerdefinierte Komponente erstellen, sondern eine wiederverwendbare Komponente, die aus einer Gruppe vorhandener Steuerelemente besteht, -Komponente (oder Verbundsteuerelement) am besten geeignet ist. Zusammenfassend lässt sich sagen, atomare Steuerelemente oder Ansichten zu einer logischen Gruppe von Elementen zusammenfassen, die als eine Sache behandelt werden können. Ein Kombinationsfeld kann beispielsweise eine Kombination aus einem einzeiligen EditText-Feld sein und eine angrenzende Schaltfläche mit angehängter Pop-up-Liste. Wenn Nutzende auf die Schaltfläche tippen und etwas aus in der Liste enthält, werden sie im Feld EditText gefüllt. Sie können aber auch etwas eingeben, direkt in den EditText, wenn sie dies bevorzugen.

In Android sind hierfür zwei andere Ansichten verfügbar: Spinner und AutoCompleteTextView. Unabhängig davon ist dieses Konzept für ein Kombinationsfeld ein gutes Beispiel.

So erstellen Sie eine zusammengesetzte Komponente:

  • Wie bei Activity müssen Sie entweder den deklarativen (XML-basierten) Ansatz verwenden. um die enthaltenen Komponenten zu erstellen oder programmatisch aus Ihrem Code zu verschachteln. Die Üblicher Ausgangspunkt ist irgendeine Art Layout. Erstellen Sie also eine Klasse, die eine Layout Im Fall eines Kombinationsfelds können Sie ein LinearLayout mit horizontale Ausrichtung. Sie können andere Layouts darin verschachteln, sodass die zusammengesetzte Komponente beliebig komplex und strukturiert ist.
  • Im Konstruktor für die neue Klasse nehmen Sie die Parameter, die die übergeordnete Klasse erwartet, und übergeben Sie an den Superklassen-Konstruktor übergeben. Dann können Sie die anderen zu verwendenden Ansichten in Ihrer neuen Komponente. Hier erstellen Sie das Feld EditText und den Pop-up-Liste. Sie können eigene Attribute und Parameter in die XML-Datei einfügen, die Ihr abrufen und verwenden kann.
  • Optional können Sie Listener für Ereignisse erstellen, die von den enthaltenen Ansichten generiert werden könnten. Ein Beispiel ist ein Listener-Methode für den Klick-Listener des Listenelements zum Aktualisieren des Inhalts der EditText, wenn eine Listenauswahl getroffen wurde.
  • Optional können Sie eigene Attribute mit Zugriffsfunktionen und Modifikatoren erstellen. Lassen Sie zum Beispiel Der Wert EditText wird anfangs in der Komponente festgelegt und fragt den Inhalt ab, wenn erforderlich.
  • Optional können Sie onDraw() und onMeasure() überschreiben. Dies ist normalerweise nicht erforderlich, Erweiterung eines Layout, da das Layout ein Standardverhalten aufweist, das wahrscheinlich problemlos funktioniert.
  • Sie haben auch die Möglichkeit, andere on-Methoden wie onKeyDown() zu überschreiben, um z. B. bestimmte Standardwerte aus der Pop-up-Liste eines Kombinationsfelds, wenn auf eine bestimmte Taste getippt wird.

Die Verwendung eines Layout als Grundlage für ein benutzerdefiniertes Steuerelement bietet viele Vorteile. einschließlich der folgenden:

  • Wie bei einem Aktivitätsbildschirm können Sie das Layout mithilfe der deklarativen XML-Dateien festlegen. oder Sie können Ansichten programmatisch erstellen und aus Ihrem Code im Layout verschachteln.
  • Die Methoden onDraw() und onMeasure() sowie die meisten anderen on-Methoden haben ein geeignetes Verhalten, sodass Sie sie nicht überschreiben müssen.
  • Sie können schnell beliebig komplexe zusammengesetzte Ansichten erstellen und sie so wiederverwenden, als wären sie eine Komponente.

Vorhandenen Ansichtstyp ändern

Wenn es eine Komponente gibt, die Ihren Vorstellungen ähnlich ist, können Sie diese Komponente erweitern und Verhalten, das Sie ändern möchten. Alles, was Sie tun, können Sie mit einer vollständig angepassten Wenn Sie mit einer spezialisierteren Klasse in der View-Hierarchie beginnen, ein Verhalten zu erhalten, das genau das tut, was Sie wollen.

Beispiel: Der Parameter Notepad Beispiel-App demonstriert viele Aspekte der Verwendung der Android-Plattform. Dazu gehört die Erweiterung eines EditText-Ansicht, um einen ausgefüllten Notizblock zu erstellen. Dies ist kein perfektes Beispiel. dies kann sich ändern, aber es verdeutlicht die Prinzipien.

Falls Sie dies noch nicht getan haben, importieren Sie das NotePad-Beispiel in Android Studio oder sehen Sie sich die über den angegebenen Link. Lies dir insbesondere die Definition von LinedEditText durch. in der NoteEditor.java -Datei.

Beachten Sie in dieser Datei Folgendes:

  1. Die Definition

    Die Klasse wird mit der folgenden Zeile definiert:
    public static class LinedEditText extends EditText

    LinedEditText ist als innere Klasse innerhalb von NoteEditor definiert Aktivität, die aber öffentlich ist, sodass als NoteEditor.LinedEditText darauf zugegriffen werden kann von außerhalb der Klasse NoteEditor.

    Außerdem hat LinedEditText den Wert static, was bedeutet, dass kein sogenannte „synthetische Methoden“ mit der sie auf Daten der übergeordneten Klasse zugreifen kann. Das bedeutet, dass es verhält sich als separate Klasse und nicht als etwas eng mit NoteEditor verwandtes Element. Dies ist eine sauberere Methode, um innere Klassen zu erstellen, wenn sie keinen Zugriff auf den Status aus dem der äußeren Klasse. Die generierte Klasse bleibt klein und kann problemlos von anderen Klassen.

    LinedEditText erweitert EditText. Dies ist die Ansicht, in der angepasst werden soll. in diesem Fall. Wenn Sie fertig sind, kann die neue Klasse eine normale EditText-Klasse ersetzen. Ansicht.

  2. Klasseninitialisierung

    Wie immer wird der Super zuerst aufgerufen. Dies ist kein Standardkonstruktor, sondern ein parametrisiert werden. Die EditText wird mit diesen Parametern erstellt, wenn sie die aus einer XML-Layoutdatei überhöht wurden. Der Konstruktor muss sie daher aufnehmen und an auch den Konstruktor der Basisklasse an.

  3. Überschriebene Methoden

    In diesem Beispiel wird nur die Methode onDraw() überschrieben, Sie müssen jedoch möglicherweise wie Sie Ihre eigenen benutzerdefinierten Komponenten erstellen.

    In diesem Beispiel können Sie durch das Überschreiben der onDraw()-Methode die blauen Linien auf EditText-Ansichts-Canvas. Das Canvas-Element wird an das überschriebene onDraw()-Methode. Die Methode super.onDraw() wird vor dem Aufruf endet. Die Methode der übergeordneten Klasse muss aufgerufen werden. Rufen Sie sie in diesem Fall am Ende zeichnen Sie die Linien, die Sie einfügen möchten.

  4. Benutzerdefinierte Komponente

    Sie haben jetzt Ihre benutzerdefinierte Komponente. Aber wie können Sie sie verwenden? Im NotePad-Beispiel zeigt der benutzerdefinierte Komponente direkt aus dem deklarativen Layout verwendet wird. note_editor.xml in der res/layout Ordner:

    <view xmlns:android="http://schemas.android.com/apk/res/android"
        class="com.example.android.notepad.NoteEditor$LinedEditText"
        android:id="@+id/note"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:padding="5dp"
        android:scrollbars="vertical"
        android:fadingEdge="vertical"
        android:gravity="top"
        android:textSize="22sp"
        android:capitalize="sentences"
    />
    

    Die benutzerdefinierte Komponente wird als generische Ansicht in der XML-Datei erstellt und die Klasse wird angegeben. mit dem vollständigen Paket. Auf die von Ihnen definierte innere Klasse wird mithilfe der NoteEditor$LinedEditText-Notation, mit der sich standardmäßig auf die innere in der Programmiersprache Java.

    Wenn Ihre benutzerdefinierte Ansichtskomponente nicht als innere Klasse definiert ist, können Sie die Ansicht deklarieren Komponente mit dem XML-Elementnamen und schließen Sie das Attribut class aus. Für Beispiel:

    <com.example.android.notepad.LinedEditText
      id="@+id/note"
      ... />
    

    Beachten Sie, dass die Klasse LinedEditText jetzt eine separate Klassendatei ist. Wenn der Parameter Klasse ist in der Klasse NoteEditor verschachtelt, funktioniert diese Technik nicht.

    Bei den anderen Attributen und Parametern in der Definition handelt es sich um die, die an die benutzerdefinierte und wird dann an den EditText-Konstruktor übergeben. Es sind dieselben Parameter, die Sie für eine EditText-Ansicht verwenden. Es ist möglich, Ihre eigenen Parameter verwenden.

Das Erstellen benutzerdefinierter Komponenten ist immer komplizierter.

Eine komplexere Komponente kann noch mehr on-Methoden überschreiben und ihre eigene Hilfsmethoden nutzen, bei denen Eigenschaften und Verhalten im Wesentlichen angepasst werden. Die einzige Grenze ist Ihre und was Sie mit der Komponente tun können.