如何获取在代码中的attrs.xml中创建的枚举


108

我创建了一个自定义视图(在此处查找),其声明类型为enum。在xml中,我现在可以为我的自定义属性选择一个枚举条目。现在,我想创建一个以编程方式设置此值的方法,但是我无法访问该枚举。

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); 但是我找不到枚举,或者甚至不知道如何获取枚举或枚举的名称。

Answers:


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

现在像其他枚举变量一样使用方向。


最后,只需使用此方法即可获取枚举属性:TypedArray.getInt(R.styleable.name_your_define,defaultValue)
CalvinChe

@CalvinChe,返回一个int。史蒂夫·莫雷兹(Steve Moretz)拥有了。我没看到它感到愚蠢,但这是凌晨4:30。上床睡觉的时间……
37分

是的,就这么简单。答案只是一个更好地说明它的例子。
史蒂夫·莫雷兹

2
但这只是对符号进行了两个并行定义。仅当定义相同时,它才有效-也就是说,它是脆弱的。OP希望代码访问从XML生成的枚举。似乎应该有可能。
史蒂夫·怀特

@SteveWhite因为您无权访问xml,所以没有办法使其自动化并使其依赖于一个定义,这是实现它的最简洁(可能)的方法。可能很棒,但是却不能。(除非可以但不能在代码中,您可以编写一个插件来读取xml并将值提取到Java中,这样它将被同步化,是的,这样就不会脆弱因为它是自动化的。)
史蒂夫·莫雷兹

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
我认为在这里依靠枚举序数注定会创建不可靠的代码。一件事会被更新,而另一件事不会被更新,那么您将遇到麻烦。
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 
}

现在获取枚举很简单:

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

4

我知道问题发布已经有一段时间了,但是最近我也遇到了同样的问题。我一起破解了一些东西,这些东西使用Square的JavaPoet和build.gradle中的一些东西,这些东西会在项目构建时从attrs.xml自动创建Java枚举类。

https://github.com/afterecho/create_enum_from_xml上有一个小演示和自述文件,其中有解释

希望能帮助到你。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.