So erhalten Sie eine Aufzählung, die in attrs.xml im Code erstellt wird


108

Ich habe eine benutzerdefinierte Ansicht ( hier zu finden ) mit einem deklarierbaren Attribut vom Typ enum erstellt. In XML kann ich jetzt einen der Aufzählungseinträge für mein benutzerdefiniertes Attribut auswählen. Jetzt möchte ich eine Methode erstellen, um diesen Wert programmgesteuert festzulegen, kann jedoch nicht auf die Aufzählung zugreifen.

attr.xml

<declare-styleable name="IconView">
    <attr name="icon" format="enum">
        <enum name="enum_name_one" value="0"/>
        ....
        <enum name="enum_name_n" value="666"/>
   </attr>
</declare-styleable>     

layout.xml

<com.xyz.views.IconView
    android:id="@+id/heart_icon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:icon="enum_name_x"/>

Was ich brauche ist so etwas wie: mCustomView.setIcon(R.id.enum_name_x); Aber ich kann die Aufzählung nicht finden oder ich habe sogar keine Ahnung, wie ich die Aufzählung oder die Namen der Aufzählung bekommen kann.

Antworten:


99

Es scheint keine automatisierte Möglichkeit zu geben, eine Java-Enumeration aus einer Attribut-Enumeration abzurufen. In Java können Sie den von Ihnen angegebenen numerischen Wert abrufen. Die Zeichenfolge wird in XML-Dateien verwendet (wie Sie zeigen).

Sie können dies in Ihrem Ansichtskonstruktor tun:

TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.IconView,
                0, 0);

    // Gets you the 'value' number - 0 or 666 in your example
    if (a.hasValue(R.styleable.IconView_icon)) {
        int value = a.getInt(R.styleable.IconView_icon, 0));
    }

    a.recycle();
}

Wenn Sie den Wert in eine Aufzählung aufnehmen möchten, müssen Sie den Wert entweder selbst einer Java-Aufzählung zuordnen, z.

private enum Format {
    enum_name_one(0), enum_name_n(666);
    int id;

    Format(int id) {
        this.id = id;
    }

    static Format fromId(int id) {
        for (Format f : values()) {
            if (f.id == id) return f;
        }
        throw new IllegalArgumentException();
    }
}

Dann könnten Sie im ersten Codeblock Folgendes verwenden:

Format format = Format.fromId(a.getInt(R.styleable.IconView_icon, 0))); 

(Obwohl das Auslösen einer Ausnahme an dieser Stelle möglicherweise keine gute Idee ist, ist es wahrscheinlich besser, einen vernünftigen Standardwert zu wählen.)


38

Es ist ganz einfach, zeigen wir allen ein Beispiel, um zu zeigen, wie einfach es ist:

attr.xml:

<declare-styleable name="MyMotionLayout">
    <attr name="motionOrientation" format="enum">
        <enum name="RIGHT_TO_LEFT" value="0"/>
        <enum name="LEFT_TO_RIGHT" value="1"/>
        <enum name="TOP_TO_BOTTOM" value="2"/>
        <enum name="BOTTOM_TO_TOP" value="3"/>
    </attr>
</declare-styleable>

Benutzerdefiniertes Layout:

public enum Direction {RIGHT_TO_LEFT, LEFT_TO_RIGHT, TOP_TO_BOTTOM, BOTTOM_TO_TOP}
Direction direction;
...
    TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.MyMotionLayout);
    Direction direction = Direction.values()[ta.getInt(R.styleable.MyMotionLayout_motionOrientation,0)];

Verwenden Sie jetzt die Richtung wie jede andere Aufzählungsvariable.


Verwenden Sie abschließend einfach Enum attr: TypedArray.getInt (R.styleable.name_your_define, defaultValue)
CalvinChe

@CalvinChe ,, das gibt ein int. Steve Moretz hat es. Ich fühle mich dumm, es nicht zu sehen, aber es ist 4:30 Uhr . Zeit fürs Bett ...
n00dles

Ja, genauso einfach. Die Antwort war nur ein Beispiel, um es besser zu veranschaulichen.
Steve Moretz

2
Dies macht jedoch nur zwei parallele Definitionen von Symbolen. Dies funktioniert nur, solange die Definitionen identisch sind - das heißt, es ist fragil. Das OP erwartete Codezugriff auf eine aus XML generierte Aufzählung. Es scheint, dass dies möglich sein sollte.
Steve White

@SteveWhite Da Sie keinen Zugriff auf XML haben, gibt es keine Möglichkeit, diese zu automatisieren und von einer Definition abhängig zu machen. Dies ist der sauberste (mögliche) Weg, dies zu erreichen. Wenn Sie die XML analysieren und auf diese Weise darauf zugreifen könnten könnte großartig sein, aber du kannst es nicht. (Wenn du es nicht kannst, aber nicht im Code, kannst du ein Plugin schreiben, um die XML zu lesen und die Werte in dein Java zu extrahieren, damit es synchronisiert wird, also ja, auf diese Weise wird es nicht zerbrechlich weil es automatisiert ist.)
steve moretz

13

Gut um der Vernunft willen. Stellen Sie sicher, dass Ihre Ordnungszahlen in Ihrem deklarierten Stil identisch sind wie in Ihrer Enum-Deklaration, und greifen Sie als Array darauf zu.

TypedArray a = context.getTheme().obtainStyledAttributes(
                   attrs,
                   R.styleable.IconView,
                   0, 0);

int ordinal = a.getInt(R.styleable.IconView_icon, 0);

if (ordinal >= 0 && ordinal < MyEnum.values().length) {
      enumValue = MyEnum.values()[ordinal];
}

3
Ich denke, dass das Verlassen auf Ordnungszahlen dazu bestimmt ist, unzuverlässigen Code zu erstellen. Eine Sache wird aktualisiert und nicht die andere, und dann werden Sie Probleme haben.
Tir38

1
Was ist ein besserer Weg, dies zu tun?
Jonathan

6

Lassen Sie mich eine in Kotlin geschriebene Lösung hinzufügen. Inline-Erweiterungsfunktion hinzufügen:

inline fun <reified T : Enum<T>> TypedArray.getEnum(index: Int, default: T) =
    getInt(index, -1).let { if (it >= 0) enumValues<T>()[it] else default 
}

Jetzt ist es einfach, eine Aufzählung zu erhalten:

val a: TypedArray = obtainStyledAttributes(...)
val yourEnum: YourEnum = a.getEnum(R.styleable.YourView_someAttr, YourEnum.DEFAULT)
a.recycle()

4

Ich weiß, dass es eine Weile her ist, seit die Frage veröffentlicht wurde, aber ich hatte kürzlich das gleiche Problem. Ich habe etwas zusammen gehackt, das JavaPoet von Square und einige Dinge in build.gradle verwendet, die beim Erstellen eines Projekts automatisch eine Java-Enum-Klasse aus attrs.xml erstellen.

Es gibt eine kleine Demo und eine Readme-Datei mit einer Erklärung unter https://github.com/afterecho/create_enum_from_xml

Ich hoffe es hilft.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.