Kodda attrs.xml'de oluşturulan bir enum nasıl elde edilir


109

Enum türünün bildirilen stili bir özniteliğiyle özel bir Görünüm ( burada bulun ) oluşturdum. Xml'de artık özel özniteliğim için enum girdilerinden birini seçebilirim. Şimdi bu değeri programlı olarak ayarlamak için bir yöntem oluşturmak istiyorum, ancak numaralandırmaya erişemiyorum.

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

İhtiyacım olan şey şuna benzer: mCustomView.setIcon(R.id.enum_name_x); Ama numaralandırmayı bulamıyorum ya da numaralandırmayı veya numaralandırmanın isimlerini nasıl elde edebileceğimi bile bilmiyorum.

Yanıtlar:


100

Bir öznitelik numaralandırmasından Java enum almanın otomatik bir yolu yok gibi görünüyor - Java'da belirttiğiniz sayısal değeri alabilirsiniz - dize XML dosyalarında (gösterdiğiniz gibi) kullanmak içindir.

Bunu görünüm oluşturucunuzda yapabilirsiniz:

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

Değeri bir numaralandırma içinde istiyorsanız, değeri kendiniz bir Java numarasına eşlemeniz gerekir, örneğin:

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

Daha sonra ilk kod bloğunda şunları kullanabilirsiniz:

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

(bu noktada bir istisna atmak harika bir fikir olmayabilir, ancak makul bir varsayılan değer seçmek muhtemelen daha iyidir)


38

Çok basit Haydi herkese ne kadar kolay olduğunu göstermek için bir örnek gösterelim:

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>

Özel düzen:

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

şimdi diğer numaralandırma değişkenleri gibi yön kullanın.


Sonuç olarak, bunu Enum attr: TypedArray.getInt (R.styleable.name_your_define, defaultValue)
CalvinChe

@CalvinChe ,, bu bir int. Steve Moretz'de var. Görmediğim için kendimi aptal gibi hissediyorum ama saat 4:30 .
Yatma

Evet, bu kadar basit. Cevap, onu daha iyi göstermek için sadece bir örnekti.
steve moretz

2
Ancak bu, simgelerin iki paralel tanımını yapar. Bu, yalnızca tanımlar aynı olduğu sürece işe yarar - yani kırılgan. OP, XML'den oluşturulan bir numaralandırmaya kod erişimi bekliyordu. Görünüşe göre bu mümkün olmalı.
Steve White

@SteveWhite xml'ye erişiminiz olmadığından, onu otomatikleştirmenin ve tek bir tanıma bağlı kalmasına izin vermenin bir yolu yoktur. Bunu başarmanın en temiz (mümkün) yolu budur. Xml'yi ayrıştırıp ona erişebilecek şekilde harika olabilir ama yapamazsınız. (Kodda yapamıyorsanız, yapamıyorsanız, xml'yi okumak ve değerleri java'nıza çıkarmak için bir eklenti yazabilirsiniz, böylece senkronize edilir, böylece evet, bu şekilde kırılgan olmaz çünkü otomatiktir.)
steve moretz

13

Akıl sağlığı için. Sıra sayılarınızın, Enum bildiriminizdeki gibi bildirilen biçemde aynı olduğundan emin olun ve ona bir dizi olarak erişin.

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
Bence burada enum sıra değerlerine güvenmek, güvenilmez kod yaratmaktır. Bir şey güncellenecek, diğeri değil ve sonra sorun yaşarsınız.
tir38

1
peki bunu yapmanın daha iyi bir yolu nedir?
Jonathan

6

Kotlin ile yazılmış bir çözüm ekleyeyim. Satır içi uzantı işlevi ekleyin:

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

Şimdi numaralandırmak basittir:

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

4

Sorunun yayınlanmasından bu yana uzun zaman geçtiğini biliyorum, ancak son zamanlarda aynı sorunu yaşadım. Square'in JavaPoet'ini ve build.gradle'da proje derlemesinde attrs.xml'den otomatik olarak bir Java enum sınıfı oluşturan bazı şeyleri kullanan küçük bir şeyi birlikte hackledim.

Https://github.com/afterecho/create_enum_from_xml adresinde küçük bir demo ve açıklamalı bir benioku var

Umarım yardımcı olur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.