Eigene View mit XML-Attributen

Aus Byte-Welt Wiki
Version vom 23. Juli 2018, 14:52 Uhr von L-ectron-X (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springenZur Suche springen

In diesem Artikel wird erklärt, wie ihr eine eigene View erstellen könnt, die durch XML-Attribute beeinflussbar ist. Mit dieser Technik können ähnliche Komponenten zusammengefasst und als eine einzige gut wiederverwendet werden.

Eigenes XML-Attribut

Damit wir mit einem eigenen Attribut arbeiten können muss es zuerst angelegt werden. Das geschieht in einer Resourcen-xml-Datei die sich im Ordner values befindet. In selbigem Ordner findet man oft z.B. auch folgende Dateien: strings.xml, styles.xml. Um Ordnung im Projekt zu halten empfielt es sich hier eine neue XML anzulegen mit dem Namen: attrs.xml (dort kann man dann alle Attribute sammeln).

<!-- attrs.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TutorialView">
        <attr name="info" format="string" />
    </declare-styleable>
</resources>
declare-styleable
Mit diesem Tag können wir mehrer Attribute kapseln. Declare-styleable benötigt einen Namen und am besten nehmen wir hierzu den Namen der View (in unserem Fall: TutorialView)
attr
Mit diesem Tag definieren wir unser Attribut unter Angabe des Namens und Format. Welche Formate zur Verfügung stehen verratet euch die IDE. Ansonsten gibt es hier noch eine ausführlichere Erklärung dazu: stackoverflow - Defining custom attrs

Die View-Klasse

Um eine eigene View zu erstellen, brauchen wir zunächst eine Klasse. Diese sollte mindestens von View erben. In diesem Artikel werden wir von einem LinearLayout ausgehen. Unser neuer View wird sich also aus bestehenden Views zusammensetzen.

Der Konstruktor

Damit der View in einer XML verwendet werden kann, benötigt er einen entsprechenden Konstruktor. Denn Android nutzt zum erstellen des View-Objektes immer folgenden Konstruktor:

public <constructor>(Context context, AttributeSet attrs) {

}

Dabei stehen unsere XML-Daten in dem AttributeSet-Objekt. Da es sein kann, dass man direkt in Java mal ein Objekt von der View-Klasse erstellen möchten, sollten wir noch einen Konstruktor bereitstellen mit nur einem Parameter (Context).

XML-Attribut in View auswerten

Die Auswertung unseres XML-Attributes wird an folgendem Beispiel erklärt:

public class TutorialView extends LinearLayout {

    public TutorialView(Context context) {
        this(context, null);
    }

    public TutorialView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {      
        TextView textView = new TextView(context);
        textView.setText("Foo bar");
        addView(textView);
    }
}

Hier möchten wir das der TextView den Wert des Attributes übernimmt, welches wir zuvor im Abschnitt Eigenes XML-Attribut bereits angelegt haben. Um an eben diesen Wert zu kommen, müssen wir mit dem AttributeSet arbeiten. Mit einem TypedArray können wir sehr elegant und einfach arbeiten. Deswegen erstellen wir uns eines mit folgendem Aufruf:

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TutorialView);

Der Methode obtainStyledAttributes übergeben wir zwei Werte. Zuerst die Informationen aus dem XML und danach was wir aus dem XML haben möchten (das R.styleable.TutorialView repräsentiert hier den XML-Tag "declared-styleable" und dessen Inhalt).

Jetzt wo wir unser TypedArray haben sollten wir immer daran denken, dieses wieder frei zu geben. Dazu solltet Ihr die Methode recycle() aufrufen - sobald ihr das Objekt nicht mehr benötigt:

typedArray.recycle();

Der letzte Schritt ist dann, den Wert auslesen. Dies geht einfach mit folgender Codezeile:

String infoText = typedArray.getString(R.styleable.TutorialView_info);

getString sollte selbsterklärend sein, dennoch der Hinweis: wird im XML anstelle eines String eine Ressource (z.B.: @string/app_name) angegeben, so liefert getString den Inhalt der Ressource zurück.

Vollständige Klasse (Beispiel)

Zur Vollständigkeit ist hier nochmal die komplette Klasse:

public class TutorialView extends LinearLayout {

    public TutorialView(Context context) {
        this(context, null);
    }

    public TutorialView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TextView textView = new TextView(context);

        if(attrs != null) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TutorialView);
            textView.setText(typedArray.getString(R.styleable.TutorialView_info));
            typedArray.recycle();
        }

        addView(textView);
    }
}

Verwendung im Layout

Um den View im Layout nutzen zu können, reicht es bereits Ihn über seinen vollqualifizierten Namen anzusprechen:

<de.jfruit.tutorial.TutorialView
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      />

damit wir hier unser Attribut nutzen können, müssen wir zuerst noch einen weiteren XML-Namespace angeben. Dazu passen wir einfach das Root-Element an indem wir folgendes Attribut hinzufügen:

xmlns:app="http://schemas.android.com/apk/res-auto"

Dabei kann der Name des Namespaces (hier: app) frei gewählt werden. Wichtig ist nur, dass wir diesen Namespacenamen immer vor unser eigenes Attribut (durch Doppelpunkt getrennt) schreiben. In unserem Falle sähe das dann wie folgt aus:

app:info="@string/app_name"

Vollständige Layout-XML (Beispiel)

Und hier seht Ihr das komplette Layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent">


    <de.jfruit.tutorial.TutorialView
            app:info="@string/app_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />
</LinearLayout>

Damit sind wir fertig. Unser View kann in einer XML verwendet und angepasst werden.

Video-Tutorial

Zu diesem Thema habe ich auch ein Videotutorial gemacht. Dieses findet Ihr hier:Android - Eigene View + XML