How to get an enum which is created in attrs.xml in code

后端 未结 5 1825
小蘑菇
小蘑菇 2020-12-23 20:30

I created a custom View (find it here) with an declare-styleable attribute of type enum. In xml I can now choose one of the enum entries for my custom attribute. Now I want

相关标签:
5条回答
  • 2020-12-23 20:32

    Let me add a solution written in kotlin. Add inline extension function:

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

    Now getting enum is simple:

    val a: TypedArray = obtainStyledAttributes(...)
    val yourEnum: YourEnum = a.getEnum(R.styleable.YourView_someAttr, YourEnum.DEFAULT)
    a.recycle()
    
    0 讨论(0)
  • 2020-12-23 20:32

    I know it's been a while since the question was posted, but I had the same issue recently. I hacked a little something together that uses Square's JavaPoet and some stuff in the build.gradle that automatically creates a Java enum class from the attrs.xml on project build.

    There's a little demo and a readme with an explanation at https://github.com/afterecho/create_enum_from_xml

    Hope it helps.

    0 讨论(0)
  • 2020-12-23 20:33

    It's simple let's show everybody an example just to show how easy it is:

    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>
    

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

    now use direction like any other enumeration variable.

    0 讨论(0)
  • 2020-12-23 20:34

    There does not seem to be an automated way to get a Java enum from an attribute enum - in Java you can get the numeric value you specified - the string is for use in XML files (as you show).

    You could do this in your view constructor:

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

    If you want the value into an enum you would need to either map the value into a Java enum yourself, e.g.:

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

    Then in the first code block you could use:

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

    (though throwing an exception at this point may not be a great idea, probably better to choose a sensible default value)

    0 讨论(0)
  • 2020-12-23 20:45

    Well for sanity's sake. Make sure your ordinals are the same in your declared styleable as in your Enum declaration and access it as an array.

    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];
    }
    
    0 讨论(0)
提交回复
热议问题