コードでattrs.xmlに作成された列挙型を取得する方法


108

enum型のdeclare-styleable属性を持つカスタムビュー(ここでそれを見つける)を作成しました。xmlで、カスタム属性の列挙型エントリの1つを選択できるようになりました。プログラムでこの値を設定するメソッドを作成したいのですが、列挙型にアクセスできません。

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"/>

必要なのは次のようなものです。mCustomView.setIcon(R.id.enum_name_x); しかし、列挙型が見つからないか、列挙型または列挙型の名前を取得する方法がわかりません。

回答:


100

属性列挙からJava列挙を取得する自動化された方法はないようです。Javaでは指定した数値を取得できます。文字列はXMLファイルで使用するためのものです(表示)。

あなたはあなたのビューコンストラクタでこれを行うことができます:

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();
}

値を列挙型にしたい場合は、値をJava列挙型に自分でマッピングする必要があります。例:

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();
    }
}

次に、最初のコードブロックで使用できます。

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

(この時点で例外をスローすることは良い考えではないかもしれませんが、おそらく適切なデフォルト値を選択する方が良いでしょう)


38

それは簡単です。それがどれほど簡単かを示すために、すべての人に例を示しましょう。

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>

カスタムレイアウト:

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)];

他の列挙型変数と同様に方向を使用するようになりました。


結論として、これを使用してEnum属性を取得します:TypedArray.getInt(R.styleable.name_your_define、defaultValue)
CalvinChe

@CalvinChe ,,それはを返しますint。スティーブ・モレッツはそれを持っています。見ないのはバカな感じです午前4時半です。ベッドの時間
...-n00dles

答えはそれと同じくらい簡単です。答えはそれをよりよく説明するための単なる例でした。
steve moretz

2
しかし、これはシンボルの2つの並列定義を作成するだけです。これが機能するのは、定義が同一である、つまり壊れやすい場合だけです。OPは、XMLから生成された列挙型へのコードアクセスを期待していました。それは可能だと思われます。
スティーブホワイト

@SteveWhiteにはxmlへのアクセス権がないため、それを自動化して1つの定義に依存させる方法はありません。これは、それを達成するための最もクリーンな(可能性のある)方法です。xmlを解析して、素晴らしいかもしれませんが、できない場合があります(コードでできないができない場合は、xmlを読み取り、Javaに値を抽出するプラグインを作成して、同期されるようにすることで、脆弱にならないようにすることができます自動化されているからです。)
steve moretz

13

まあ、正気のために。序数がEnum宣言と同じように宣言されたスタイル設定で同じであることを確認し、配列としてアクセスします。

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
ここで列挙型序数に依存することは、信頼できないコードを作成することになると思います。1つは更新され、もう1つは更新されないため、問題が発生します。
tir38

1
それを行うためのより良い方法は何ですか?
ジョナサン

6

kotlinで書かれたソリューションを追加しましょう。インライン拡張関数を追加します。

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

enumを取得するのは簡単です。

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

4

質問が投稿されてからしばらく経っていますが、最近同じ問題が発生しました。SquareのJavaPoetとプロジェクトのビルド時にattrs.xmlからJava enumクラスを自動的に作成するbuild.gradleのいくつかのものを使用する少し何かを一緒にハッキングしました。

https://github.com/afterecho/create_enum_from_xmlに説明付きの小さなデモとReadmeがあります。

それが役に立てば幸い。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.