Dapatkan nilai warna secara terprogram jika itu adalah referensi (tema)


116

Pertimbangkan ini:

styles.xml

<style name="BlueTheme" parent="@android:style/Theme.Black.NoTitleBar">
    <item name="theme_color">@color/theme_color_blue</item>
</style>

attrs.xml

<attr name="theme_color" format="reference" />

color.xml

<color name="theme_color_blue">#ff0071d3</color>

Jadi warna tema dirujuk oleh temanya. Bagaimana saya bisa mendapatkan theme_color (referensi) secara terprogram? Biasanya saya akan menggunakan getResources().getColor()tetapi tidak dalam kasus ini karena direferensikan!

Jawaban:


255

Ini harus melakukan pekerjaan itu:

TypedValue typedValue = new TypedValue();
Theme theme = context.getTheme();
theme.resolveAttribute(R.attr.theme_color, typedValue, true);
@ColorInt int color = typedValue.data;

Pastikan juga untuk menerapkan tema ke Aktivitas Anda sebelum memanggil kode ini. Salah satu penggunaan:

android:theme="@style/Theme.BlueTheme"

dalam manifes atau panggilan (sebelum Anda menelepon setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

masuk onCreate().

Saya telah mengujinya dengan nilai-nilai Anda dan berhasil dengan sempurna.


terima kasih Saya belum dapat mencoba solusi Anda karena saya mendapatkan kesalahan: stackoverflow.com/questions/17278244/… Mungkin Anda memiliki pengalaman dalam hal ini ...
Seraphim's

5
Bagaimanapun, dengan solusi Anda, saya mendapatkan 0 nilai warna (TypedValue {t = 0x0 / d = 0x0}) ... Saya tidak menggunakan decare-styleable, hanya referensi ke warna
Seraphim's

Apakah Anda menerapkan tema tersebut pada aktivitas Anda?
Emanuel Moecklin

5
Jika Anda tidak ingin menerapkan tema ke aktivitas, Anda bisa membuat ContextThemeWrappermenggunakan id tema dan kemudian mengambil tema darinya.
Ted Hopp

1
Metode ini berfungsi di Android X (perancangan material)
BlackBlind

43

Untuk menambah jawaban yang diterima, jika Anda menggunakan kotlin.

@ColorInt
fun Context.getColorFromAttr(
    @AttrRes attrColor: Int,
    typedValue: TypedValue = TypedValue(),
    resolveRefs: Boolean = true
): Int {
    theme.resolveAttribute(attrColor, typedValue, resolveRefs)
    return typedValue.data
}

dan kemudian dalam aktivitas Anda, Anda dapat melakukannya

textView.setTextColor(getColorFromAttr(R.attr.color))


2
oook, terima kasih untuk "integrasi". Saya tidak menggunakan kotlin tapi menarik.
Seraphim

5
Yah itu membuat TypedValue terlihat oleh dunia luar. Dan untuk warna Anda selalu ingin menyelesaikan deklarasi referensial, jadi saya punya ini: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }(diformat dengan buruk di sini tapi tidak apa-apa)
milosmns

1
Penggunaannya akan seperti ini:val errorColor = context.getThemeColor(R.attr.colorError)
milosmns

Cara yang lebih universal, yang juga mengambil nilai default untuk ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(dari Nick Butcher )
gmk57

Cara pamungkas, yang mengambil keseluruhan ColorStateList, bahkan jika itu mereferensikan atribut tema lain: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(warna tunggal juga akan dibungkus ColorStateList).
gmk57

24

Ini berhasil untuk saya:

int[] attrs = {R.attr.my_attribute};
TypedArray ta = context.obtainStyledAttributes(attrs);
int color = ta.getResourceId(0, android.R.color.black);
ta.recycle();

jika Anda ingin mengeluarkan hexstring darinya:

Integer.toHexString(color)

Ini harus mengembalikan ColorRes, bukan ColorInt.
Miha_x64

Saya akhirnya menggunakan ini dengan getColorResource (color) dan tidak memanggil daur ulang.
Zeek Aran

2

Jika Anda ingin mendapatkan banyak warna, Anda dapat menggunakan:

int[] attrs = {R.attr.customAttr, android.R.attr.textColorSecondary, 
        android.R.attr.textColorPrimaryInverse};
Resources.Theme theme = context.getTheme();
TypedArray ta = theme.obtainStyledAttributes(attrs);

int[] colors = new int[attrs.length];
for (int i = 0; i < attrs.length; i++) {
    colors[i] = ta.getColor(i, 0);
}

ta.recycle();

2

Tambahkan ini ke build.gradle (app) Anda:

implementation 'androidx.core:core-ktx:1.1.0'

Dan tambahkan fungsi ekstensi ini di suatu tempat di kode Anda:

@ColorInt
@SuppressLint("Recycle")
fun Context.themeColor(
    @AttrRes themeAttrId: Int
): Int {
    return obtainStyledAttributes(
        intArrayOf(themeAttrId)
    ).use {
        it.getColor(0, Color.MAGENTA)
    }
}

0

Berikut adalah metode utilitas Java ringkas yang mengambil banyak atribut dan mengembalikan larik bilangan bulat warna. :)

/**
 * @param context    Pass the activity context, not the application context
 * @param attrFields The attribute references to be resolved
 * @return int array of color values
 */
@ColorInt
static int[] getColorsFromAttrs(Context context, @AttrRes int... attrFields) {
    int length = attrFields.length;
    Resources.Theme theme = context.getTheme();
    TypedValue typedValue = new TypedValue();

    @ColorInt int[] colorValues = new int[length];

    for (int i = 0; i < length; ++i) {
        @AttrRes int attr = attrFields[i];
        theme.resolveAttribute(attr, typedValue, true);
        colorValues[i] = typedValue.data;
    }

    return colorValues;
}

Java lebih baik dari Kotlin untuk ini?
IgorGanapolsky

@IgorGanapolsky Oh, sejujurnya saya tidak tahu. Saya membagikan kode saya karena saya tahu itu akan berguna bagi seseorang di luar sana! Saya tidak tahu Kotlin dan saya berasumsi bahwa Kotlin tidak akan membuatnya bekerja lebih baik, mungkin lebih sedikit baris kode! : P
varun

-1

Bagi mereka yang mencari referensi untuk ditarik Anda harus menggunakan falsediresolveRefs

theme.resolveAttribute(R.attr.some_drawable, typedValue, **false**);


Apa variabel typedValue yang dirujuk?
BENN1TH

Apa yang dimaksud dengan tema variabel. *?
BENN1TH
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.