कोड में attrs.xml में बनाई गई एक एनम कैसे प्राप्त करें


108

मैंने एक कस्टम व्यू बनाया (इसे यहां देखें ) टाइप एनम की एक घोषित-शैलीगत विशेषता के साथ। 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); लेकिन मुझे एनम नहीं मिल रहा है या मुझे यह भी पता नहीं है कि मुझे एनम या एनम के नाम कैसे मिल सकते हैं।

जवाबों:


100

एक विशेषता एनम से जावा एनम प्राप्त करने के लिए एक स्वचालित तरीका प्रतीत नहीं होता है - जावा में आप निर्दिष्ट संख्यात्मक मान प्राप्त कर सकते हैं - स्ट्रिंग 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();
}

यदि आप एक एनम में मान चाहते हैं, तो आपको या तो जावा एनम में मान को मैप करना होगा, जैसे:

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 attr पाने के लिए बस इसका उपयोग करें: TypedArray.getInt (R.styleable.name_your_define, defaultValue)
केल्विन

@CalvinChe ,, कि एक रिटर्न int। स्टीव Moretz यह है। मैं इसे न देखने के लिए गूंगा महसूस करता हूं, लेकिन यह 4:30 बजे है । बिस्तर के लिए समय ...
n00dles

हाँ बस के रूप में सरल है। इसका जवाब यह बेहतर उदाहरण के लिए सिर्फ एक उदाहरण था।
स्टेव मोरेट

2
लेकिन यह सिर्फ प्रतीकों की दो समानांतर परिभाषा करता है। यह केवल इतनी देर तक काम करता है जब तक परिभाषाएं समान होती हैं - अर्थात, यह नाजुक है। ओपी एक्सएमएल से उत्पन्न एनम तक कोड पहुंच की उम्मीद कर रहा था। ऐसा लगता है कि यह संभव होना चाहिए।
स्टीव व्हाइट

@SteveWhite चूंकि आपके पास xml तक कोई पहुंच नहीं है, इसलिए इसे स्वचालित करने का कोई तरीका नहीं है और इसे एक परिभाषा पर निर्भर रहने दें। यह प्राप्त करने का सबसे साफ (संभव) तरीका है। यदि आप xml को पार्स कर सकते हैं और इसे इस तरह से एक्सेस कर सकते हैं महान हो सकता है, लेकिन आप ऐसा नहीं कर सकते। (जब तक आप नहीं कर सकते, लेकिन कोड में नहीं, आप xml को पढ़ने के लिए एक प्लगइन लिख सकते हैं और अपने जावा को मान निकाल सकते हैं, इसलिए इसे सिंक्रोनाइज़ किया जाएगा ताकि हाँ यह उस तरह से नाजुक न हो। क्योंकि यह स्वचालित है)।
स्टीव 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
मुझे लगता है कि एनम अध्यादेशों पर भरोसा करना अविश्वसनीय कोड बनाने के लिए किस्मत में है। एक चीज अपडेट हो जाएगी और दूसरी नहीं और फिर आपको परेशानी होगी।
tir38

1
तो यह करने का एक बेहतर तरीका क्या है?
जोनाथन

6

मुझे कोटलिन में लिखा एक समाधान जोड़ने दें। इनलाइन एक्सटेंशन फ़ंक्शन जोड़ें:

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

मुझे पता है कि प्रश्न पोस्ट किए जाने के बाद से कुछ समय हो गया है, लेकिन मेरे पास हाल ही में एक ही मुद्दा था। मैंने एक साथ कुछ हैक किया है जो स्क्वायर के JavaPoet और बिल्ड.ग्रेड में कुछ सामान का उपयोग करता है जो स्वचालित रूप से प्रोजेक्ट बिल्ड पर attrs.xml से जावा एनम क्लास बनाता है।

Https://github.com/afterecho/create_enum_frombxx पर स्पष्टीकरण के साथ थोड़ा डेमो और एक रीडमी है

आशा करता हूँ की ये काम करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.