it-swarm.com.de

Deklarieren eines benutzerdefinierten Android UI-Elements unter Verwendung von XML

Wie deklariere ich ein Android UI-Element mit XML?

464
Casebash

Das Android Developer Guide hat einen Abschnitt namens Building Custom Components . Leider behandelt die Diskussion der XML-Attribute nur das Deklarieren des Steuerelements in der Layoutdatei und nicht das tatsächliche Behandeln der Werte in der Klasseninitialisierung. Die Schritte sind wie folgt:

1. Deklarieren Sie Attribute in values\attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCustomView">
        <attr name="Android:text"/>
        <attr name="Android:textColor"/>            
        <attr name="extraInformation" format="string" />
    </declare-styleable>
</resources>

Beachten Sie die Verwendung eines nicht qualifizierten Namens im Tag declare-styleable. Nicht standardmäßige Android Attribute wie extraInformation müssen deklariert werden. In der Oberklasse deklarierte Tags sind in Unterklassen verfügbar, ohne dass sie erneut deklariert werden müssen.

2. Erstellen Sie Konstruktoren

Da es zwei Konstruktoren gibt, die ein AttributeSet für die Initialisierung verwenden, ist es zweckmäßig, eine separate Initialisierungsmethode zu erstellen, die die Konstruktoren aufrufen können.

private void init(AttributeSet attrs) { 
    TypedArray a=getContext().obtainStyledAttributes(
         attrs,
         R.styleable.MyCustomView);

    //Use a
    Log.i("test",a.getString(
         R.styleable.MyCustomView_Android_text));
    Log.i("test",""+a.getColor(
         R.styleable.MyCustomView_Android_textColor, Color.BLACK));
    Log.i("test",a.getString(
         R.styleable.MyCustomView_extraInformation));

    //Don't forget this
    a.recycle();
}

R.styleable.MyCustomView Ist eine automatisch generierte int[] Ressource, bei der jedes Element die ID eines Attributs ist. Attribute werden für jede Eigenschaft in der XML generiert, indem der Attributname an den Elementnamen angehängt wird. Beispielsweise enthält R.styleable.MyCustomView_Android_text Das Attribut Android_text Für MyCustomView. Attribute können dann aus dem TypedArray mit verschiedenen get Funktionen abgerufen werden. Wenn das Attribut nicht in dem in der XML definierten definiert ist, wird null zurückgegeben. Ausgenommen natürlich, wenn der Rückgabetyp ein Grundelement ist, wird in diesem Fall das zweite Argument zurückgegeben.

Wenn Sie nicht alle Attribute abrufen möchten, können Sie dieses Array manuell erstellen. Die ID für standard Android Attribute sind in Android.R.attr Enthalten, während Attribute für Dieses Projekt befindet sich in R.attr.

int attrsWanted[]=new int[]{Android.R.attr.text, R.attr.textColor};

Bitte beachten Sie, dass Sie in Android.R.styleable Nichts verwenden sollten , wie in diesem Thread angegeben in der Zukunft. Es ist immer noch in der Dokumentation, dass es nützlich ist, alle diese Konstanten an einer Stelle anzuzeigen.

3. Verwenden Sie es in Layoutdateien wie layout\main.xml

Fügen Sie die Namespace-Deklaration xmlns:app="http://schemas.Android.com/apk/res-auto" In das XML-Element der obersten Ebene ein. Namespaces bieten eine Methode, um Konflikte zu vermeiden, die manchmal auftreten, wenn verschiedene Schemas dieselben Elementnamen verwenden (weitere Informationen finden Sie unter this article . Die URL ist einfach eine Möglichkeit, Schemata eindeutig zu identifizieren - es muss eigentlich nichts unter dieser URL gehostet werden . Wenn dies anscheinend nichts bewirkt, müssen Sie das Namespace-Präfix nur dann hinzufügen, wenn Sie einen Konflikt lösen müssen.

<com.mycompany.projectname.MyCustomView
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:background="@Android:color/transparent"
    Android:text="Test text"
    Android:textColor="#FFFFFF"
    app:extraInformation="My extra information"
/> 

Verweisen Sie mit dem vollständig qualifizierten Namen auf die benutzerdefinierte Ansicht.

Android LabelView Sample

Wenn Sie ein vollständiges Beispiel wünschen, sehen Sie sich das Beispiel für die Android label view an.

LabelView.Java

 TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
 CharSequences=a.getString(R.styleable.LabelView_text);

attrs.xml

<declare-styleable name="LabelView">
    <attr name="text"format="string"/>
    <attr name="textColor"format="color"/>
    <attr name="textSize"format="dimension"/>
</declare-styleable>

custom_view_1.xml

<com.example.Android.apis.view.LabelView
    Android:background="@drawable/blue"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    app:text="Blue" app:textSize="20dp"/>

Dies ist in einem LinearLayout mit einem Namespace-Attribut enthalten: xmlns:app="http://schemas.Android.com/apk/res-auto"

Links

833
Casebash

Großartige Referenz. Vielen Dank! Eine Ergänzung dazu:

Wenn Sie zufällig ein Bibliotheksprojekt haben, das benutzerdefinierte Attribute für eine benutzerdefinierte Ansicht deklariert hat, müssen Sie Ihren Projektnamensraum deklarieren, nicht den der Bibliothek. Z.B:

Vorausgesetzt, die Bibliothek hat das Paket "com.example.library.customview" und das Arbeitsprojekt hat das Paket "com.example.customview", dann:

Funktioniert nicht (zeigt den Fehler "Fehler: Keine Ressourcenkennung für Attribut 'newAttr' im Paket 'com.example.library.customview' gefunden"):

<com.library.CustomView
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        xmlns:app="http://schemas.Android.com/apk/res/com.example.library.customview"
        Android:id="@+id/myView"
        app:newAttr="value" />

Wird funktionieren:

<com.library.CustomView
        xmlns:Android="http://schemas.Android.com/apk/res/Android"
        xmlns:app="http://schemas.Android.com/apk/res/com.example.customview"
        Android:id="@+id/myView"
        app:newAttr="value" />
90
Andy

Ergänzung zu der am häufigsten gewählten Antwort.

receiveStyledAttributes ()

Ich möchte einige Worte über die Verwendung von receiveStyledAttributes () hinzufügen, wenn wir eine benutzerdefinierte Ansicht mit vordefinierten Android: xxx-Attributen erstellen. Besonders wenn wir TextAppearance verwenden.
Wie in "2. Erstellen von Konstruktoren" erwähnt, erhält die benutzerdefinierte Ansicht bei ihrer Erstellung AttributeSet. Die Hauptverwendung sehen wir im TextView-Quellcode (API 16).

final Resources.Theme theme = context.getTheme();

// TextAppearance is inspected first, but let observe it later

TypedArray a = theme.obtainStyledAttributes(
            attrs, com.Android.internal.R.styleable.TextView, defStyle, 0);

int n = a.getIndexCount();
for (int i = 0; i < n; i++) 
{
    int attr = a.getIndex(i);
    // huge switch with pattern value=a.getXXX(attr) <=> a.getXXX(a.getIndex(i))
}
a.recycle();

Was können wir hier sehen?
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
Attributmenge wird gemäß Dokumentation thematisch abgearbeitet. Attributwerte werden Schritt für Schritt zusammengestellt. Zuerst werden Attribute aus dem Thema gefüllt, dann werden Werte durch Werte aus dem Stil ersetzt, und schließlich werden andere durch exakte Werte aus XML für eine spezielle Ansichtsinstanz ersetzt.
Array angeforderter Attribute - com.Android.internal.R.styleable.TextView
Es ist eine gewöhnliche Anordnung von Konstanten. Wenn wir Standardattribute anfordern, können wir dieses Array manuell erstellen.

Was in der Dokumentation nicht erwähnt wird - Reihenfolge der Ergebnisse TypedArray-Elemente.
Wenn die benutzerdefinierte Ansicht in attrs.xml deklariert wird, werden spezielle Konstanten für Attributindizes generiert. Und wir können Werte auf diese Weise extrahieren: a.getString(R.styleable.MyCustomView_Android_text). Für manual int[] Gibt es jedoch keine Konstanten. Ich nehme an, dass getXXXValue (arrayIndex) gut funktionieren wird.

Und die andere Frage lautet: "Wie können wir interne Konstanten ersetzen und Standardattribute anfordern?" Wir können Android.R.attr. * Werte verwenden.

Wenn wir also das Standardattribut TextAppearance in der benutzerdefinierten Ansicht verwenden und dessen Werte im Konstruktor lesen möchten, können wir den Code in TextView folgendermaßen ändern:

ColorStateList textColorApp = null;
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;

Resources.Theme theme = context.getTheme();

TypedArray a = theme.obtainStyledAttributes(attrs, R.styleable.CustomLabel, defStyle, 0);
TypedArray appearance = null;
int apResourceId = a.getResourceId(R.styleable.CustomLabel_Android_textAppearance, -1);
a.recycle();
if (apResourceId != -1)
{
    appearance = 
        theme.obtainStyledAttributes(apResourceId, new int[] { Android.R.attr.textColor, Android.R.attr.textSize, 
            Android.R.attr.typeface, Android.R.attr.textStyle });
}
if (appearance != null)
{
    textColorApp = appearance.getColorStateList(0);
    textSize = appearance.getDimensionPixelSize(1, textSize);
    typefaceIndex = appearance.getInt(2, -1);
    styleIndex = appearance.getInt(3, -1);

    appearance.recycle();
}

Wo CustomLabel definiert ist:

<declare-styleable name="CustomLabel">
    <!-- Label text. -->
    <attr name="Android:text" />
    <!-- Label text color. -->
    <attr name="Android:textColor" />
    <!-- Combined text appearance properties. -->
    <attr name="Android:textAppearance" />
</declare-styleable>

Vielleicht irre ich mich irgendwie, aber Android Dokumentation zu receiveStyledAttributes () ist sehr schlecht.

Erweiterung der Standard-UI-Komponente

Gleichzeitig können wir die Standard-UI-Komponente mit allen deklarierten Attributen erweitern. Dieser Ansatz ist nicht so gut, da beispielsweise TextView viele Eigenschaften deklariert. Und es wird unmöglich sein, die volle Funktionalität beim Überschreiben von onMeasure () und onDraw () zu implementieren.

Aber wir können die theoretische Weiterverwendung von benutzerdefinierten Komponenten opfern. Sagen Sie "Ich weiß genau, welche Funktionen ich verwenden werde" und teilen Sie den Code mit niemandem.

Dann können wir den Konstruktor CustomComponent(Context, AttributeSet, defStyle) implementieren. Nach dem Aufruf von super(...) werden alle Attribute analysiert und sind über Getter-Methoden verfügbar.

26
yuriy.weiss

Es scheint, dass Google seine Entwicklerseite aktualisiert und dort verschiedene Schulungen hinzugefügt hat.

Einer von ihnen befasst sich mit der Erstellung von benutzerdefinierten Ansichten und kann gefunden werden hier

11
mitch000001

Vielen Dank für die erste Antwort.

Ich hatte nur ein Problem damit. Beim Aufblasen meiner Ansicht hatte ich einen Fehler: Java.lang.NoSuchMethodException: MyView (Kontext, Attribute)

Ich habe es gelöst, indem ich einen neuen Konstruktor erstellt habe:

public MyView(Context context, AttributeSet attrs) {
     super(context, attrs);
     // some code
}

Hoffe das wird helfen!

5
user2346922

Sie können jede Layout-Datei in andere Layout-Datei-

             <RelativeLayout
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:layout_marginLeft="10dp"
                Android:layout_marginRight="30dp" >

                <include
                    Android:id="@+id/frnd_img_file"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    layout="@layout/include_imagefile"/>

                <include
                    Android:id="@+id/frnd_video_file"
                    Android:layout_width="wrap_content"
                    Android:layout_height="wrap_content"
                    layout="@layout/include_video_lay" />

                <ImageView
                    Android:id="@+id/downloadbtn"
                    Android:layout_width="30dp"
                    Android:layout_height="30dp"
                    Android:layout_centerInParent="true"
                    Android:src="@drawable/plus"/>
            </RelativeLayout>

in diesem Fall handelt es sich bei den Layoutdateien im Include-Tag um andere XML-Layoutdateien im selben Res-Ordner.

0
Akshay Paliwal