Eigene View mit XML-Attributen: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
(Die Seite wurde neu angelegt: „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 Kompon…“)
 
K
 
(3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 4: Zeile 4:
 
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).
 
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).
  
<code=xml>
+
<syntaxhighlight lang="xml">
 
<!-- attrs.xml -->
 
<!-- attrs.xml -->
 
<?xml version="1.0" encoding="utf-8"?>
 
<?xml version="1.0" encoding="utf-8"?>
Zeile 12: Zeile 12:
 
     </declare-styleable>
 
     </declare-styleable>
 
</resources>
 
</resources>
</code=xml>
+
</syntaxhighlight>
  
 
; declare-styleable  
 
; declare-styleable  
Zeile 26: Zeile 26:
 
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:
 
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:
  
<code=java>
+
<syntaxhighlight lang="java">
 
public <constructor>(Context context, AttributeSet attrs) {
 
public <constructor>(Context context, AttributeSet attrs) {
  
 
}
 
}
</code=java>
+
</syntaxhighlight>
  
 
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).
 
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).
Zeile 36: Zeile 36:
 
==XML-Attribut in View auswerten==
 
==XML-Attribut in View auswerten==
 
Die Auswertung unseres XML-Attributes wird an folgendem Beispiel erklärt:
 
Die Auswertung unseres XML-Attributes wird an folgendem Beispiel erklärt:
<code=java>
+
<syntaxhighlight lang="java">
 
public class TutorialView extends LinearLayout {
 
public class TutorialView extends LinearLayout {
  
Zeile 54: Zeile 54:
 
     }
 
     }
 
}
 
}
</code=java>
+
</syntaxhighlight>
  
 
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 [http://developer.android.com/reference/android/content/res/TypedArray.html TypedArray] können wir sehr elegant und einfach arbeiten. Deswegen erstellen wir uns eines mit folgendem Aufruf:
 
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 [http://developer.android.com/reference/android/content/res/TypedArray.html TypedArray] können wir sehr elegant und einfach arbeiten. Deswegen erstellen wir uns eines mit folgendem Aufruf:
<code=java>
+
<syntaxhighlight lang="java">
 
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TutorialView);
 
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TutorialView);
</code=java>
+
</syntaxhighlight>
  
 
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).  
 
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).  
Zeile 65: Zeile 65:
 
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:
 
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:
  
<code=java>
+
<syntaxhighlight lang="java">
 
typedArray.recycle();
 
typedArray.recycle();
</code=java>
+
</syntaxhighlight>
  
 
Der letzte Schritt ist dann, den Wert auslesen. Dies geht einfach mit folgender Codezeile:
 
Der letzte Schritt ist dann, den Wert auslesen. Dies geht einfach mit folgender Codezeile:
<code=java>
+
<syntaxhighlight lang="java">
 
String infoText = typedArray.getString(R.styleable.TutorialView_info);
 
String infoText = typedArray.getString(R.styleable.TutorialView_info);
</code=java>
+
</syntaxhighlight>
  
 
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.
 
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.
Zeile 78: Zeile 78:
 
==Vollständige Klasse (Beispiel)==
 
==Vollständige Klasse (Beispiel)==
 
Zur Vollständigkeit ist hier nochmal die komplette Klasse:
 
Zur Vollständigkeit ist hier nochmal die komplette Klasse:
<code=java>
+
<syntaxhighlight lang="java">
 
public class TutorialView extends LinearLayout {
 
public class TutorialView extends LinearLayout {
  
Zeile 102: Zeile 102:
 
     }
 
     }
 
}
 
}
</code=java>
+
</syntaxhighlight>
  
 
=Verwendung im Layout=
 
=Verwendung im Layout=
 
Um den View im Layout nutzen zu können, reicht es bereits Ihn über seinen vollqualifizierten Namen anzusprechen:
 
Um den View im Layout nutzen zu können, reicht es bereits Ihn über seinen vollqualifizierten Namen anzusprechen:
<code=xml>
+
<syntaxhighlight lang="xml">
 
<de.jfruit.tutorial.TutorialView
 
<de.jfruit.tutorial.TutorialView
 
       android:layout_width="match_parent"
 
       android:layout_width="match_parent"
 
       android:layout_height="wrap_content"
 
       android:layout_height="wrap_content"
 
       />
 
       />
</code=xml>
+
</syntaxhighlight>
 
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:
 
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:
<code=xml>xmlns:app="http://schemas.android.com/apk/res-auto"</code=xml>
+
<syntaxhighlight lang="xml">xmlns:app="http://schemas.android.com/apk/res-auto"</syntaxhighlight>
 
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:
 
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:
<code=xml>app:info="@string/app_name"</code=xml>
+
<syntaxhighlight lang="xml">app:info="@string/app_name"</syntaxhighlight>
  
 
==Vollständige Layout-XML (Beispiel)==
 
==Vollständige Layout-XML (Beispiel)==
 
Und hier seht Ihr das komplette Layout:
 
Und hier seht Ihr das komplette Layout:
<code=xml>
+
<syntaxhighlight lang="xml">
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 
               xmlns:app="http://schemas.android.com/apk/res-auto"
 
               xmlns:app="http://schemas.android.com/apk/res-auto"
Zeile 132: Zeile 132:
 
             />
 
             />
 
</LinearLayout>
 
</LinearLayout>
</code=xml>
+
</syntaxhighlight>
  
 
Damit sind wir fertig. Unser View kann in einer XML verwendet und angepasst werden.  
 
Damit sind wir fertig. Unser View kann in einer XML verwendet und angepasst werden.  

Aktuelle Version vom 23. Juli 2018, 14:52 Uhr

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