Eigene View mit XML-Attributen
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.
Inhaltsverzeichnis
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